Introduction
The Seaside Hotel has asked to build a machine learning model which can predict booking cancellations based on the available data. This report aims to identify the best model by comparing different models and their performance. A final model will be recommended, which the hotel can implement and deploy, as a means to optimize the planning of staff, inventory and marketing efforts.
Data understanding
The Seaside Hotel has provided a train data set on which several models can be trained and evaluated. The target variable that should be predicted is is_cancelled. This target variable contains two classes: yes and no. The data shows that there is some imbalance in these classes, around 42% and 58% respectively. Therefore, the AUC metric is used instead of Accuracy to select models during model training. The class imbalance is also important to take into consideration when making the class predictions.
The entire data set is split into two smaller sets, namely a train set of 60% and a test set of 40%. Stratified splitting was used for this, meaning that the proportions of the classes of the target variable in the sets are similar to that of the entire data set. There are 23799 observations in the train set and 15864 observations in the test set. For now, the test set is set aside and will only be used after the models have been trained.
When exploring the data, some insights could be derived. The data contains no metadata nor variables that could potentially introduce data leakage. Also no major issues with multicollinearity could be found when assessing whether there are predictors which are highly correlated with one other (Appendix 6.7). Thus, no features are removed beforehand.
After looking at the distributions of the classes of the target variable for the numerical variables, one can already get an idea of what could be potentially promising features (Appendix 6.7). For example, the lead time and number of required parking spaces could possibly be good predictors for whether a person will cancel a booking or not, due to the good separation of classes. Despite these initial insights, all features are considered when building the predictive models.
When looking at the categorical variables in the data (Appendix 6.8), mainly country seems to have many categories (137 in total). Thus, multiple categories will be consolidated to significantly reduce the number of infrequent categories. Moreover, meal, market_segment, deposit_type and customer_type each have a category with a relatively low frequency (p < 0.01). These categories will also be combined with another category, as to prevent potential problems when resampling.
Model selection
To determine what the best predictive model is, different models are trained using a train set, after which their performance is evaluated using the test set.
As mentioned earlier, preprocessing is first done by merging some categories together and then dummy encoding all categorical variables after. Yeo-Johnson transformations were applied to numerical variables, since they also contain zero’s. This will make features that are skew, less skew. The recipe, containing these preprocessing steps, was prepared on the train set and then baked on the train set as well as on the test set. No normalization was needed for the machine learning models that were trained in this report. The recipe can be found in Appendix 6.1.
Model training
This section will dive deeper into the trained models. The models were trained using the smaller train set. See Appendix 6.2-6.5 for the code of the models.
Cross-validation was performed besides using a separate test set for model assessment. Where applicable, the one standard error rule is applied to select the value of the tuning parameter. To provide an overview, the following settings were used to train the models:
| Resampling method |
Cross-validation |
| Number of folds |
10 |
| Selection method |
One standard error rule |
| Metric |
AUC |
Backward stepwise regression
A glm model with backward stepwise feature selection was trained, using 10-fold cross-validation. The AIC indicated which predictors make the model more complicated. The final model resulting from this training had a ROC of 0.891. The 10 most important variables according to this model can be seen below.
| |
Overall |
| total_of_special_requests |
33.64804 |
| country_PRT |
29.29297 |
| lead_time |
27.58251 |
| previous_cancellations |
15.74839 |
| deposit_type_Non.Refund |
13.41066 |
| adr |
12.45370 |
| market_segment_Online.TA |
12.28345 |
| country_ITA |
12.09257 |
| country_other |
11.69210 |
| country_CHN |
11.55897 |
This shows that the most important predictor for whether a booking will be canceled or not, is the number of special requests. The lead time is also a good predictor, as could also be seen earlier during data exploration. Moreover, the countries Portugal, Italy and China also seem to be good predictors for is_cancelled.
Lasso regression
Next, a lasso regression was trained, also using 10-fold cross validation. This model is also able to identify (ir)relevant variables by shrinking those that don’t have a lot of influence on is_cancelled towards 0. The optimal model was selected using the one SE rule and had a lambda value of 0.0023357 and ROC of 0.889. The selected value of lambda can be seen in the following graph as well:

The estimated coefficients of the final models showed that 11 variables out of the 53 were set to 0. Months such as March, October and November were removed. Reason for that could be because these months fall in the low season of the hotel industry. When looking at the importance of variables, a few conclusions can be made. In this model, the deposit type Non-refund is the most important predictor. This predictor was also in the top 5 of most important variables in the backward stepwise regression. Furthermore, the total number of special requests, Portugal, China, previous cancellations and the online travel agent market segment are considered important in both models when comparing them in terms of variable importance. As such, there are a good number of predictors on which both models agree that they are relevant in predicting hotel bookings cancellations.
| |
Overall |
| deposit_type_Non.Refund |
4.2873172 |
| required_car_parking_spaces |
3.5369380 |
| total_of_special_requests |
3.0081430 |
| country_PRT |
1.6439634 |
| meal_other |
1.5036620 |
| previous_cancellations |
1.3156475 |
| country_CHN |
1.1433875 |
| market_segment_Online.TA |
1.0976499 |
| country_BRA |
0.7003225 |
| customer_type_Transient.Party |
0.6474984 |
Decision tree
A decision tree was build and trained using 10-fold cross validation. The selected model had a value of 0.003726 for cp with a ROC of 0.875. Pruning was performed using the one standard error rule. The decision tree looks as follows:

The variable importance in this model can be seen in the table below. Again, consistent with previous models deposit_type_Non.Refund, total_of_special_requests, country_PRT, lead_time, previous_cancellations, market_segment_Online.TA and customer_type_Transient.Party seem to be important predictors.
| |
Overall |
| deposit_type_Non.Refund |
3160.1062 |
| total_of_special_requests |
2325.2752 |
| country_PRT |
2213.5471 |
| lead_time |
2087.6614 |
| previous_cancellations |
1287.8414 |
| market_segment_Online.TA |
595.2344 |
| arrival_date_year |
526.5245 |
| market_segment_Other |
381.7769 |
| required_car_parking_spaces |
266.7346 |
| customer_type_Transient.Party |
252.5998 |
Boosted classification tree
Lastly, a boosted classification tree was trained using 10-fold cross validation. The tuning grid to train the model was as follows:
| Boosting iterations |
1000, 2500, 3000 |
| Interaction depth |
1, 2, 3 |
| Shrinkage |
0.01, 0.1 |
A summary of the training results can be seen below:

The final model that was eventually selected based on the one SE rule has 1000 boosting iterations, an interaction depth of 3, and a shrinkage parameter of 0.01. The corresponding ROC is 0.9118397. One tree in this model is showed below. From the plot, we can see that deposit type Non-refund is used to make the first split in the tree.
Model performance
In this section, an assessment is done on how well the models are able to predict on the smaller test set that was created in an earlier stage. After making the predictions, confusion matrices were created for each model to see how they perform. The decision threshold was set to 0.42, as to calculate the correct Accuracy. Using the default will result in a higher Accuracy, but the models will be biased towards the majority class. This can lead to erroneous conclusions about the predictions made. Please find below the performance metrics for each model.
Overview of model performance
| Accuracy |
0.8137 |
0.8105 |
0.8272 |
0.8523 |
| Cohen’s kappa |
0.6076 |
0.6081 |
0.6385 |
0.6971 |
| Sensitivity |
0.8315 |
0.7842 |
0.8333 |
0.8168 |
| Specificity |
0.8041 |
0.7531 |
0.8237 |
0.8786 |
| Precision |
0.6941 |
0.7531 |
0.7324 |
0.8328 |
| Recall |
0.8315 |
0.7842 |
0.8333 |
0.8168 |
| F1 |
0.7566 |
0.7683 |
0.7796 |
0.8247 |
Based on the Accuracy, the boosted classification tree seems to perform the best, followed by the decision tree. The backward stepwise regression comes close behind, whilst the lasso regression has the lowest Accuracy. The other metrics also give a good indication of how well the models perform. The performance of the models will be visualized to get a better idea which model really performs the best.
ROC and AUC
When plotting the ROC curves for the models, it becomes more clear that the gradient boosting model indeed performs the best as its curve lies above all others. The decision tree seems to have a range where it performs worse than all other models.

Below are also the AUCs of the models. The boosted classification tree has a very good score and also has the highest one. The AUC of the lasso regression and backward stepwise regression are very close to one other, whereas the decision tree has the lowest AUC out of all. Thus, the decision tree doesn’t perform as good as the other models based on the AUC, and opposed to what the Accuracy indicated earlier.
| Model |
AUC |
| d_tree |
0.8693387 |
| lasso |
0.8909033 |
| step_glm |
0.8919130 |
| xgb |
0.9325870 |
Class separation
In the following figures, one can see the class distributions for each model. From these graphs, the gradient boosting model, lasso regression and backward stepwise regression seem to do a good job in separating the classes. The decision tree has some more overlap between the classes and thus, may not be able to separate the classes as good as the others. This is consistent with our former observations.

Cumulative gain
The figure below shows the cumulative gain charts for the models. The upper dashed grey line is the best possible scenario, and would mean that the classifier is able to rank the test cases perfectly. The dashed grey line underneath is the worst case scenario, and would mean that the classifier ranks randomnly. When comparing the lines of the models, the boosted classification tree performs best once again. The lines of the backward stepwise regression and lasso regression are almost identical.

In this section, the results showed that the boosted classification tree clearly outperforms the other models. Therefore, this model was selected for evaluation in the final part of the report.
Final model
The hotel owner of the Seaside hotel has provided a final test set. This section will reveal the performance of the selected model on the predictions for this test set. The final model was trained on the entire train data set first before making the predictions using the trained model. The ROC on the entire train data set is now 0.913.
The table below provides an overview of the performance metrics of the gradient boosting model, which made predictions on the final test set.
| Accuracy |
0.8504 |
| Cohen’s kappa |
0.6931 |
| Sensitivity |
0.8150 |
| Specificity |
0.8766 |
| Precision |
0.8298 |
| Recall |
0.8150 |
| F1 |
0.8223 |
The final Accuracy is 0.8504, which indicates that the model predicted quite well on the test set. Opposed to Accuracy, a high F1 score indicates low false positives and negatives. It is therefore also a measure of how well the model can correctly identify real threats, and is in this case - with a value of 0.822 - considered good. The sensitivity-specificity and precision-recall also reflect a good predictive ability of the model. Taking the AUC in consideration as well, it again shows an excellent score for the gradient boosting model:
| Model |
AUC |
| final_xgb |
0.9314404 |
As seen in the figure below, there is a clear distinction between the classes. It can therefore be concluded that this model is able to separate the classes well.

Below is the cumulative gain chart for the gradient boosting model on the final test set. This graph shows that the model can identify about 60% of the cancellations with just 25% of the test set.

Conclusion
This report looked at subset selection-, regularization-, decision tree- and ensemble methods to build a predictive model for the Seaside Hotel, as a means to forecast booking cancellations.
After training several different models on the train set and comparing their performance, it can be concluded that the gradient boosting model performed best out of all. Therefore, this model was selected to predict the test set. For this model, Yeo-Johnson transformations were performed on the predictors, and the total number of categories were reduced to a great extent. 10 fold cross-validation was used on the train set to find the optimal tuning parameters, and the one standard error rule was applied to find a simpler model which is not significantly worse than the absolute best. Eventually, the final gradient boosting model had 1000 iterations, an interaction depth of 3 and a shrinkage value of 0.01. The results indicated a good predictive performance of the model.
Ensembles such as boosting models are usually considered highly accurate compared to for example decision trees, which are prone to overfitting. This can explain the good performance of the gradient boosting model. The cost of this model is the limited interpretability. The other three models that were assessed in this report are in such case better. Good interpretability can provide a better understanding of the features that may or may not be good predictors of is_cancelled. Because of this, the three respective models were able to give more insight into the potential drivers of hotel cancellations. One of them is for example the lead time between the booking date and the arrival date. Bookings that are guaranteed with a full deposit (Non-refund) can give an early indication of whether a booking will be canceled or not. Furthermore, bookings made through an online travel agent also seemed to be a good predictor for booking cancellations. The same goes for previous cancellations and the number of special requests. These insights can help the hotel further in their marketing efforts. For example, by providing offers to those that are likely to cancel.
When it comes to staff and inventory planning however, the boosted classification tree will provide more useful and accurate predictions. Although the final gradient boosting model performs well, there are some points of improvement for future iterations. It is recommended to use more computing power to try more and different models, to find a better model. The selected values for the tuning parameters were on the edge of the grid. For example, an interaction depth of more than 3 could potentially lead to a better performance. As such, it is recommended to iterate on more intensive models.
Appendix
Preprocessing recipe
bookings_recipe <- recipe(is_cancelled ~ ., data = bookings_train_small) %>%
step_other(country, threshold = 0.01) %>%
step_other(meal, market_segment, deposit_type, customer_type, threshold = 0.01) %>%
step_dummy(all_nominal(), -is_cancelled) %>%
step_YeoJohnson(all_numeric())
bookings_recipe_prep <- bookings_recipe %>% prep(data = bookings_train_small)
bookings_train_baked <- bookings_recipe_prep %>% bake(new_data = bookings_train_small)
bookings_test_baked <- bookings_recipe_prep %>% bake(new_data = bookings_test_small)
bookings_final_train_baked <- bookings_recipe_prep %>% bake(new_data = bookings_train)
bookings_final_test_baked <- bookings_recipe_prep %>% bake(new_data = bookings_test_solutions)
Model 1: Backward stepwise selection
set.seed(1603)
step_glm <- train(is_cancelled ~ .,
data = bookings_train_baked,
method = "glmStepAIC",
family = binomial(),
trControl = ctrl,
metric = "ROC")
step_glm
Model 2: Lasso regression
tuneGrid_lasso <- expand.grid(alpha = 1, lambda = 10^(seq(from = -4, to = -2, length.out = 20)))
set.seed(1603)
lasso <- train(is_cancelled ~ .,
data = bookings_train_baked,
method = "glmnet",
family = "binomial",
trControl = ctrl,
tuneGrid = tuneGrid_lasso,
metric = "ROC")
lasso
coef(lasso$finalModel, 0.002335721)
54 x 1 sparse Matrix of class "dgCMatrix"
1
(Intercept) -155.07403234
lead_time 0.16096513
arrival_date_year 0.07501466
arrival_date_week_number .
arrival_date_day_of_month .
stays_in_weekend_nights 0.24790511
stays_in_week_nights 0.17868090
adults .
children .
babies 0.06065662
is_repeated_guest -0.03038507
previous_cancellations 1.31564758
previous_bookings_not_cancelled -0.18079370
booking_changes -0.33299026
days_in_waiting_list .
adr 0.04325121
required_car_parking_spaces -3.53693821
total_of_special_requests -3.00814300
arrival_date_month_August 0.03084553
arrival_date_month_December 0.07791437
arrival_date_month_February 0.17798813
arrival_date_month_January 0.11906021
arrival_date_month_July -0.16763701
arrival_date_month_June -0.12892701
arrival_date_month_March .
arrival_date_month_May -0.06518944
arrival_date_month_November .
arrival_date_month_October .
arrival_date_month_September -0.23836729
meal_None 0.26235646
meal_HB -0.13464881
meal_other 1.50366207
country_BEL -0.16127128
country_BRA 0.70032249
country_CHE -0.20307611
country_CHN 1.14338759
country_DEU -0.48600894
country_ESP 0.39858615
country_FRA -0.23968226
country_GBR .
country_IRL 0.12605389
country_ITA 0.56295118
country_NLD -0.02612917
country_PRT 1.64396345
country_USA .
country_other 0.34473001
market_segment_Offline.TA.TO -0.33081181
market_segment_Online.TA 1.09764995
market_segment_Other -0.26647306
deposit_type_Non.Refund 4.28731731
deposit_type_other .
customer_type_Transient.Party -0.64749844
customer_type_Contract -0.24161309
customer_type_other -0.29092735
Model 3: Decision tree
set.seed(1603)
d_tree <- train(is_cancelled ~ .,
data = bookings_train_baked,
method = "rpart",
tuneLength = 10,
trControl = ctrl,
metric = "ROC")
d_tree
Model 4: Boosted classification tree
tuneGrid_xgb <- expand.grid(eta = c(0.01, 0.1),
max_depth = 1:3,
colsample_bytree = 0.6,
subsample = 1,
nrounds = c(1000, 2500, 5000),
gamma = 0,
min_child_weight = 1)
set.seed(1603)
xgb <- train(is_cancelled ~ .,
data = bookings_train_baked,
method = "xgbTree",
trControl = ctrl,
tuneGrid = tuneGrid_xgb,
metric = "ROC")
xgb
Data summary
Data summary
|
|
|
|
Name
|
Piped data
|
|
Number of rows
|
23799
|
|
Number of columns
|
24
|
|
_______________________
|
|
|
Column type frequency:
|
|
|
character
|
2
|
|
factor
|
5
|
|
numeric
|
17
|
|
________________________
|
|
|
Group variables
|
None
|
Variable type: character
|
skim_variable
|
n_missing
|
complete_rate
|
min
|
max
|
empty
|
n_unique
|
whitespace
|
|
arrival_date_month
|
0
|
1
|
3
|
9
|
0
|
12
|
0
|
|
country
|
0
|
1
|
2
|
4
|
0
|
137
|
0
|
Variable type: factor
|
skim_variable
|
n_missing
|
complete_rate
|
ordered
|
n_unique
|
top_counts
|
|
is_cancelled
|
0
|
1
|
FALSE
|
2
|
no: 13869, yes: 9930
|
|
meal
|
0
|
1
|
FALSE
|
4
|
BB: 18714, Non: 3089, HB: 1983, FB: 13
|
|
market_segment
|
0
|
1
|
FALSE
|
4
|
Onl: 11526, Off: 5137, Gro: 4217, Oth: 2919
|
|
deposit_type
|
0
|
1
|
FALSE
|
3
|
No : 19886, Non: 3909, Ref: 4
|
|
customer_type
|
0
|
1
|
FALSE
|
4
|
Tra: 17770, Tra: 5242, Con: 701, Gro: 86
|
Variable type: numeric
|
skim_variable
|
n_missing
|
complete_rate
|
mean
|
sd
|
p0
|
p25
|
p50
|
p75
|
p100
|
hist
|
|
lead_time
|
0
|
1
|
109.00
|
111.05
|
0
|
22.0
|
73.00
|
162
|
629
|
▇▂▁▁▁
|
|
arrival_date_year
|
0
|
1
|
2016.17
|
0.70
|
2015
|
2016.0
|
2016.00
|
2017
|
2017
|
▃▁▇▁▆
|
|
arrival_date_week_number
|
0
|
1
|
27.24
|
13.46
|
1
|
17.0
|
27.00
|
38
|
53
|
▅▇▇▇▅
|
|
arrival_date_day_of_month
|
0
|
1
|
15.84
|
8.72
|
1
|
8.0
|
16.00
|
23
|
31
|
▇▇▇▇▆
|
|
stays_in_weekend_nights
|
0
|
1
|
0.79
|
0.89
|
0
|
0.0
|
1.00
|
2
|
16
|
▇▁▁▁▁
|
|
stays_in_week_nights
|
0
|
1
|
2.18
|
1.46
|
0
|
1.0
|
2.00
|
3
|
41
|
▇▁▁▁▁
|
|
adults
|
0
|
1
|
1.85
|
0.51
|
0
|
2.0
|
2.00
|
2
|
4
|
▁▂▇▁▁
|
|
children
|
0
|
1
|
0.09
|
0.36
|
0
|
0.0
|
0.00
|
0
|
3
|
▇▁▁▁▁
|
|
babies
|
0
|
1
|
0.01
|
0.07
|
0
|
0.0
|
0.00
|
0
|
2
|
▇▁▁▁▁
|
|
is_repeated_guest
|
0
|
1
|
0.03
|
0.16
|
0
|
0.0
|
0.00
|
0
|
1
|
▇▁▁▁▁
|
|
previous_cancellations
|
0
|
1
|
0.08
|
0.41
|
0
|
0.0
|
0.00
|
0
|
13
|
▇▁▁▁▁
|
|
previous_bookings_not_cancelled
|
0
|
1
|
0.13
|
1.78
|
0
|
0.0
|
0.00
|
0
|
70
|
▇▁▁▁▁
|
|
booking_changes
|
0
|
1
|
0.18
|
0.60
|
0
|
0.0
|
0.00
|
0
|
18
|
▇▁▁▁▁
|
|
days_in_waiting_list
|
0
|
1
|
3.35
|
21.27
|
0
|
0.0
|
0.00
|
0
|
391
|
▇▁▁▁▁
|
|
adr
|
0
|
1
|
105.42
|
52.34
|
0
|
79.2
|
99.45
|
126
|
5400
|
▇▁▁▁▁
|
|
required_car_parking_spaces
|
0
|
1
|
0.02
|
0.15
|
0
|
0.0
|
0.00
|
0
|
3
|
▇▁▁▁▁
|
|
total_of_special_requests
|
0
|
1
|
0.54
|
0.78
|
0
|
0.0
|
0.00
|
1
|
5
|
▇▁▁▁▁
|
Multicollinearity

Class distributions - Numeric variables
Data summary
|
|
|
|
Name
|
Piped data
|
|
Number of rows
|
23799
|
|
Number of columns
|
24
|
|
_______________________
|
|
|
Column type frequency:
|
|
|
character
|
2
|
|
factor
|
4
|
|
numeric
|
17
|
|
________________________
|
|
|
Group variables
|
is_cancelled
|
Variable type: character
|
skim_variable
|
is_cancelled
|
n_missing
|
complete_rate
|
min
|
max
|
empty
|
n_unique
|
whitespace
|
|
arrival_date_month
|
no
|
0
|
1
|
3
|
9
|
0
|
12
|
0
|
|
arrival_date_month
|
yes
|
0
|
1
|
3
|
9
|
0
|
12
|
0
|
|
country
|
no
|
0
|
1
|
2
|
4
|
0
|
118
|
0
|
|
country
|
yes
|
0
|
1
|
2
|
4
|
0
|
106
|
0
|
Variable type: factor
|
skim_variable
|
is_cancelled
|
n_missing
|
complete_rate
|
ordered
|
n_unique
|
top_counts
|
|
meal
|
no
|
0
|
1
|
FALSE
|
4
|
BB: 10672, Non: 1964, HB: 1230, FB: 3
|
|
meal
|
yes
|
0
|
1
|
FALSE
|
4
|
BB: 8042, Non: 1125, HB: 753, FB: 10
|
|
market_segment
|
no
|
0
|
1
|
FALSE
|
4
|
Onl: 7247, Off: 2928, Oth: 2406, Gro: 1288
|
|
market_segment
|
yes
|
0
|
1
|
FALSE
|
4
|
Onl: 4279, Gro: 2929, Off: 2209, Oth: 513
|
|
deposit_type
|
no
|
0
|
1
|
FALSE
|
3
|
No : 13861, Non: 6, Ref: 2
|
|
deposit_type
|
yes
|
0
|
1
|
FALSE
|
3
|
No : 6025, Non: 3903, Ref: 2
|
|
customer_type
|
no
|
0
|
1
|
FALSE
|
4
|
Tra: 9682, Tra: 3727, Con: 384, Gro: 76
|
|
customer_type
|
yes
|
0
|
1
|
FALSE
|
4
|
Tra: 8088, Tra: 1515, Con: 317, Gro: 10
|
Variable type: numeric
|
skim_variable
|
is_cancelled
|
n_missing
|
complete_rate
|
mean
|
sd
|
p0
|
p25
|
p50
|
p75
|
p100
|
hist
|
|
lead_time
|
no
|
0
|
1
|
79.32
|
88.98
|
0
|
11.0
|
49
|
117.0
|
518
|
▇▂▁▁▁
|
|
lead_time
|
yes
|
0
|
1
|
150.46
|
124.71
|
0
|
49.0
|
115
|
229.0
|
629
|
▇▃▂▁▁
|
|
arrival_date_year
|
no
|
0
|
1
|
2016.17
|
0.69
|
2015
|
2016.0
|
2016
|
2017.0
|
2017
|
▃▁▇▁▆
|
|
arrival_date_year
|
yes
|
0
|
1
|
2016.17
|
0.71
|
2015
|
2016.0
|
2016
|
2017.0
|
2017
|
▃▁▇▁▆
|
|
arrival_date_week_number
|
no
|
0
|
1
|
27.25
|
13.65
|
1
|
16.0
|
28
|
38.0
|
53
|
▅▇▇▇▅
|
|
arrival_date_week_number
|
yes
|
0
|
1
|
27.22
|
13.19
|
1
|
17.0
|
27
|
38.0
|
53
|
▅▇▇▇▅
|
|
arrival_date_day_of_month
|
no
|
0
|
1
|
15.80
|
8.73
|
1
|
8.0
|
16
|
23.0
|
31
|
▇▇▇▇▆
|
|
arrival_date_day_of_month
|
yes
|
0
|
1
|
15.90
|
8.70
|
1
|
8.0
|
16
|
23.0
|
31
|
▇▇▇▇▆
|
|
stays_in_weekend_nights
|
no
|
0
|
1
|
0.80
|
0.87
|
0
|
0.0
|
1
|
2.0
|
16
|
▇▁▁▁▁
|
|
stays_in_weekend_nights
|
yes
|
0
|
1
|
0.78
|
0.92
|
0
|
0.0
|
1
|
1.0
|
10
|
▇▁▁▁▁
|
|
stays_in_week_nights
|
no
|
0
|
1
|
2.13
|
1.42
|
0
|
1.0
|
2
|
3.0
|
41
|
▇▁▁▁▁
|
|
stays_in_week_nights
|
yes
|
0
|
1
|
2.26
|
1.52
|
0
|
1.0
|
2
|
3.0
|
21
|
▇▁▁▁▁
|
|
adults
|
no
|
0
|
1
|
1.83
|
0.53
|
0
|
2.0
|
2
|
2.0
|
4
|
▁▂▇▁▁
|
|
adults
|
yes
|
0
|
1
|
1.88
|
0.47
|
0
|
2.0
|
2
|
2.0
|
4
|
▁▂▇▁▁
|
|
children
|
no
|
0
|
1
|
0.09
|
0.37
|
0
|
0.0
|
0
|
0.0
|
3
|
▇▁▁▁▁
|
|
children
|
yes
|
0
|
1
|
0.08
|
0.35
|
0
|
0.0
|
0
|
0.0
|
3
|
▇▁▁▁▁
|
|
babies
|
no
|
0
|
1
|
0.01
|
0.09
|
0
|
0.0
|
0
|
0.0
|
2
|
▇▁▁▁▁
|
|
babies
|
yes
|
0
|
1
|
0.00
|
0.05
|
0
|
0.0
|
0
|
0.0
|
1
|
▇▁▁▁▁
|
|
is_repeated_guest
|
no
|
0
|
1
|
0.04
|
0.18
|
0
|
0.0
|
0
|
0.0
|
1
|
▇▁▁▁▁
|
|
is_repeated_guest
|
yes
|
0
|
1
|
0.01
|
0.12
|
0
|
0.0
|
0
|
0.0
|
1
|
▇▁▁▁▁
|
|
previous_cancellations
|
no
|
0
|
1
|
0.02
|
0.33
|
0
|
0.0
|
0
|
0.0
|
13
|
▇▁▁▁▁
|
|
previous_cancellations
|
yes
|
0
|
1
|
0.16
|
0.49
|
0
|
0.0
|
0
|
0.0
|
13
|
▇▁▁▁▁
|
|
previous_bookings_not_cancelled
|
no
|
0
|
1
|
0.20
|
2.24
|
0
|
0.0
|
0
|
0.0
|
70
|
▇▁▁▁▁
|
|
previous_bookings_not_cancelled
|
yes
|
0
|
1
|
0.03
|
0.75
|
0
|
0.0
|
0
|
0.0
|
48
|
▇▁▁▁▁
|
|
booking_changes
|
no
|
0
|
1
|
0.25
|
0.70
|
0
|
0.0
|
0
|
0.0
|
18
|
▇▁▁▁▁
|
|
booking_changes
|
yes
|
0
|
1
|
0.08
|
0.40
|
0
|
0.0
|
0
|
0.0
|
6
|
▇▁▁▁▁
|
|
days_in_waiting_list
|
no
|
0
|
1
|
2.09
|
17.15
|
0
|
0.0
|
0
|
0.0
|
379
|
▇▁▁▁▁
|
|
days_in_waiting_list
|
yes
|
0
|
1
|
5.10
|
25.85
|
0
|
0.0
|
0
|
0.0
|
391
|
▇▁▁▁▁
|
|
adr
|
no
|
0
|
1
|
105.85
|
40.91
|
0
|
80.0
|
100
|
126.0
|
510
|
▇▇▁▁▁
|
|
adr
|
yes
|
0
|
1
|
104.84
|
65.02
|
0
|
75.9
|
99
|
125.8
|
5400
|
▇▁▁▁▁
|
|
required_car_parking_spaces
|
no
|
0
|
1
|
0.04
|
0.20
|
0
|
0.0
|
0
|
0.0
|
3
|
▇▁▁▁▁
|
|
required_car_parking_spaces
|
yes
|
0
|
1
|
0.00
|
0.00
|
0
|
0.0
|
0
|
0.0
|
0
|
▁▁▇▁▁
|
|
total_of_special_requests
|
no
|
0
|
1
|
0.74
|
0.84
|
0
|
0.0
|
1
|
1.0
|
5
|
▇▂▁▁▁
|
|
total_of_special_requests
|
yes
|
0
|
1
|
0.27
|
0.59
|
0
|
0.0
|
0
|
0.0
|
5
|
▇▁▁▁▁
|
Categorical variables
| country |
n |
| AGO |
109 |
| AIA |
1 |
| ALB |
3 |
| AND |
1 |
| ARE |
14 |
| ARG |
50 |
| ARM |
3 |
| ATF |
1 |
| AUS |
91 |
| AUT |
315 |
| arrival_date_month |
n |
| April |
2208 |
| August |
2684 |
| December |
1308 |
| February |
1494 |
| January |
1122 |
| July |
2416 |
| June |
2334 |
| March |
1975 |
| May |
2462 |
| November |
1305 |
| October |
2284 |
| September |
2207 |
| meal |
n |
| BB |
18714 |
| None |
3089 |
| HB |
1983 |
| FB |
13 |
| market_segment |
n |
| Groups |
4217 |
| Offline TA/TO |
5137 |
| Online TA |
11526 |
| Other |
2919 |
| deposit_type |
n |
| No Deposit |
19886 |
| Non Refund |
3909 |
| Refundable |
4 |
| customer_type |
n |
| Transient |
17770 |
| Transient-Party |
5242 |
| Contract |
701 |
| Group |
86 |
LS0tCnRpdGxlOiAiVGhlIFNlYXNpZGUgSG90ZWwiCmF1dGhvcjogIlRpZW4gTmd1eWVuIDQ4MDQ5NCIKZGF0ZTogIk1heSAxNiwgMjAyMSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKc3VidGl0bGU6IFByZWRpY3RpdmUgbW9kZWxsaW5nIGZvciBob3RlbCBib29raW5nIGNhbmNlbGxhdGlvbnMKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQogIG1hcmtkb3duOgogICAgd3JhcDogc2VudGVuY2UKLS0tCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoImtuaXRyIikKbGlicmFyeSgic2tpbXIiKQpsaWJyYXJ5KCJjb3JycGxvdCIpCmxpYnJhcnkoImNhcmV0IikKbGlicmFyeSgicmVjaXBlcyIpCmxpYnJhcnkoImxlYXBzIikKbGlicmFyeSgiZ2xtbmV0IikKbGlicmFyeSgicnBhcnQiKQpsaWJyYXJ5KCJycGFydC5wbG90IikKbGlicmFyeSgicmFuZG9tRm9yZXN0IikKbGlicmFyeSgiZ2JtIikKbGlicmFyeSgieGdib29zdCIpCmxpYnJhcnkoImthYmxlRXh0cmEiKQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGUgU2Vhc2lkZSBIb3RlbCBoYXMgYXNrZWQgdG8gYnVpbGQgYSBtYWNoaW5lIGxlYXJuaW5nIG1vZGVsIHdoaWNoIGNhbiBwcmVkaWN0IGJvb2tpbmcgY2FuY2VsbGF0aW9ucyBiYXNlZCBvbiB0aGUgYXZhaWxhYmxlIGRhdGEuIFRoaXMgcmVwb3J0IGFpbXMgdG8gaWRlbnRpZnkgdGhlIGJlc3QgbW9kZWwgYnkgY29tcGFyaW5nIGRpZmZlcmVudCBtb2RlbHMgYW5kIHRoZWlyIHBlcmZvcm1hbmNlLiBBIGZpbmFsIG1vZGVsIHdpbGwgYmUgcmVjb21tZW5kZWQsIHdoaWNoIHRoZSBob3RlbCBjYW4gaW1wbGVtZW50IGFuZCBkZXBsb3ksIGFzIGEgbWVhbnMgdG8gb3B0aW1pemUgdGhlIHBsYW5uaW5nIG9mIHN0YWZmLCBpbnZlbnRvcnkgYW5kIG1hcmtldGluZyBlZmZvcnRzLgoKIyBEYXRhIHVuZGVyc3RhbmRpbmcKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmxvYWQoImJvb2tpbmdzX3RyYWluLlJEYXRhIikKbG9hZCgiYm9va2luZ3NfdGVzdC5SRGF0YSIpCmxvYWQoImJvb2tpbmdzX3Rlc3Rfc29sdXRpb25zLlJEYXRhIikKYGBgCgpUaGUgU2Vhc2lkZSBIb3RlbCBoYXMgcHJvdmlkZWQgYSB0cmFpbiBkYXRhIHNldCBvbiB3aGljaCBzZXZlcmFsIG1vZGVscyBjYW4gYmUgdHJhaW5lZCBhbmQgZXZhbHVhdGVkLiBUaGUgdGFyZ2V0IHZhcmlhYmxlIHRoYXQgc2hvdWxkIGJlIHByZWRpY3RlZCBpcyBgaXNfY2FuY2VsbGVkYC4gVGhpcyB0YXJnZXQgdmFyaWFibGUgY29udGFpbnMgdHdvIGNsYXNzZXM6IGB5ZXNgIGFuZCBgbm9gLiBUaGUgZGF0YSBzaG93cyB0aGF0IHRoZXJlIGlzIHNvbWUgaW1iYWxhbmNlIGluIHRoZXNlIGNsYXNzZXMsIGFyb3VuZCA0MiUgYW5kIDU4JSByZXNwZWN0aXZlbHkuIFRoZXJlZm9yZSwgdGhlIEFVQyBtZXRyaWMgaXMgdXNlZCBpbnN0ZWFkIG9mIEFjY3VyYWN5IHRvIHNlbGVjdCBtb2RlbHMgZHVyaW5nIG1vZGVsIHRyYWluaW5nLiBUaGUgY2xhc3MgaW1iYWxhbmNlIGlzIGFsc28gaW1wb3J0YW50IHRvIHRha2UgaW50byBjb25zaWRlcmF0aW9uIHdoZW4gbWFraW5nIHRoZSBjbGFzcyBwcmVkaWN0aW9ucy4KCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmJvb2tpbmdzX3RyYWluICU+JSAKICBjb3VudChpc19jYW5jZWxsZWQpICU+JSAKICBtdXRhdGUocHJvcCA9IG4gLyBucm93KGJvb2tpbmdzX3RyYWluKSkKYGBgCgpUaGUgZW50aXJlIGRhdGEgc2V0IGlzIHNwbGl0IGludG8gdHdvIHNtYWxsZXIgc2V0cywgbmFtZWx5IGEgdHJhaW4gc2V0IG9mIDYwJSBhbmQgYSB0ZXN0IHNldCBvZiA0MCUuClN0cmF0aWZpZWQgc3BsaXR0aW5nIHdhcyB1c2VkIGZvciB0aGlzLCBtZWFuaW5nIHRoYXQgdGhlIHByb3BvcnRpb25zIG9mIHRoZSBjbGFzc2VzIG9mIHRoZSB0YXJnZXQgdmFyaWFibGUgaW4gdGhlIHNldHMgYXJlIHNpbWlsYXIgdG8gdGhhdCBvZiB0aGUgZW50aXJlIGRhdGEgc2V0LiBUaGVyZSBhcmUgMjM3OTkgb2JzZXJ2YXRpb25zIGluIHRoZSB0cmFpbiBzZXQgYW5kIDE1ODY0IG9ic2VydmF0aW9ucyBpbiB0aGUgdGVzdCBzZXQuIEZvciBub3csIHRoZSB0ZXN0IHNldCBpcyBzZXQgYXNpZGUgYW5kIHdpbGwgb25seSBiZSB1c2VkIGFmdGVyIHRoZSBtb2RlbHMgaGF2ZSBiZWVuIHRyYWluZWQuCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpzZXQuc2VlZCgxNjAzKQp0cmFpbl9pbmQgPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihib29raW5nc190cmFpbiRpc19jYW5jZWxsZWQsIHAgPSAwLjYpCmJvb2tpbmdzX3RyYWluX3NtYWxsIDwtIGJvb2tpbmdzX3RyYWluICU+JSBkcGx5cjo6c2xpY2UodHJhaW5faW5kJFJlc2FtcGxlMSkKYm9va2luZ3NfdGVzdF9zbWFsbCA8LSBib29raW5nc190cmFpbiAlPiUgZHBseXI6OnNsaWNlKC10cmFpbl9pbmQkUmVzYW1wbGUxKQpgYGAKCldoZW4gZXhwbG9yaW5nIHRoZSBkYXRhLCBzb21lIGluc2lnaHRzIGNvdWxkIGJlIGRlcml2ZWQuIFRoZSBkYXRhIGNvbnRhaW5zIG5vIG1ldGFkYXRhIG5vciB2YXJpYWJsZXMgdGhhdCBjb3VsZCBwb3RlbnRpYWxseSBpbnRyb2R1Y2UgZGF0YSBsZWFrYWdlLiBBbHNvIG5vIG1ham9yIGlzc3VlcyB3aXRoIG11bHRpY29sbGluZWFyaXR5IGNvdWxkIGJlIGZvdW5kIHdoZW4gYXNzZXNzaW5nIHdoZXRoZXIgdGhlcmUgYXJlIHByZWRpY3RvcnMgd2hpY2ggYXJlIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggb25lIG90aGVyIChBcHBlbmRpeCA2LjcpLiBUaHVzLCBubyBmZWF0dXJlcyBhcmUgcmVtb3ZlZCBiZWZvcmVoYW5kLgoKQWZ0ZXIgbG9va2luZyBhdCB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgY2xhc3NlcyBvZiB0aGUgdGFyZ2V0IHZhcmlhYmxlIGZvciB0aGUgbnVtZXJpY2FsIHZhcmlhYmxlcywgb25lIGNhbiBhbHJlYWR5IGdldCBhbiBpZGVhIG9mIHdoYXQgY291bGQgYmUgcG90ZW50aWFsbHkgcHJvbWlzaW5nIGZlYXR1cmVzIChBcHBlbmRpeCA2LjcpLiBGb3IgZXhhbXBsZSwgdGhlIGxlYWQgdGltZSBhbmQgbnVtYmVyIG9mIHJlcXVpcmVkIHBhcmtpbmcgc3BhY2VzIGNvdWxkIHBvc3NpYmx5IGJlIGdvb2QgcHJlZGljdG9ycyBmb3Igd2hldGhlciBhIHBlcnNvbiB3aWxsIGNhbmNlbCBhIGJvb2tpbmcgb3Igbm90LCBkdWUgdG8gdGhlIGdvb2Qgc2VwYXJhdGlvbiBvZiBjbGFzc2VzLiBEZXNwaXRlIHRoZXNlIGluaXRpYWwgaW5zaWdodHMsIGFsbCBmZWF0dXJlcyBhcmUgY29uc2lkZXJlZCB3aGVuIGJ1aWxkaW5nIHRoZSBwcmVkaWN0aXZlIG1vZGVscy4KCldoZW4gbG9va2luZyBhdCB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGluIHRoZSBkYXRhIChBcHBlbmRpeCA2LjgpLCBtYWlubHkgYGNvdW50cnlgIHNlZW1zIHRvIGhhdmUgbWFueSBjYXRlZ29yaWVzICgxMzcgaW4gdG90YWwpLiBUaHVzLCBtdWx0aXBsZSBjYXRlZ29yaWVzIHdpbGwgYmUgY29uc29saWRhdGVkIHRvIHNpZ25pZmljYW50bHkgcmVkdWNlIHRoZSBudW1iZXIgb2YgaW5mcmVxdWVudCBjYXRlZ29yaWVzLiBNb3Jlb3ZlciwgYG1lYWxgLCBgbWFya2V0X3NlZ21lbnRgLCBgZGVwb3NpdF90eXBlYCBhbmQgYGN1c3RvbWVyX3R5cGVgIGVhY2ggaGF2ZSBhIGNhdGVnb3J5IHdpdGggYSByZWxhdGl2ZWx5IGxvdyBmcmVxdWVuY3kgKHAgXDwgMC4wMSkuIFRoZXNlIGNhdGVnb3JpZXMgd2lsbCBhbHNvIGJlIGNvbWJpbmVkIHdpdGggYW5vdGhlciBjYXRlZ29yeSwgYXMgdG8gcHJldmVudCBwb3RlbnRpYWwgcHJvYmxlbXMgd2hlbiByZXNhbXBsaW5nLgoKIyBNb2RlbCBzZWxlY3Rpb24KClRvIGRldGVybWluZSB3aGF0IHRoZSBiZXN0IHByZWRpY3RpdmUgbW9kZWwgaXMsIGRpZmZlcmVudCBtb2RlbHMgYXJlIHRyYWluZWQgdXNpbmcgYSB0cmFpbiBzZXQsIGFmdGVyIHdoaWNoIHRoZWlyIHBlcmZvcm1hbmNlIGlzIGV2YWx1YXRlZCB1c2luZyB0aGUgdGVzdCBzZXQuCgpBcyBtZW50aW9uZWQgZWFybGllciwgcHJlcHJvY2Vzc2luZyBpcyBmaXJzdCBkb25lIGJ5IG1lcmdpbmcgc29tZSBjYXRlZ29yaWVzIHRvZ2V0aGVyIGFuZCB0aGVuIGR1bW15IGVuY29kaW5nIGFsbCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYWZ0ZXIuIFllby1Kb2huc29uIHRyYW5zZm9ybWF0aW9ucyB3ZXJlIGFwcGxpZWQgdG8gbnVtZXJpY2FsIHZhcmlhYmxlcywgc2luY2UgdGhleSBhbHNvIGNvbnRhaW4gemVybydzLiBUaGlzIHdpbGwgbWFrZSBmZWF0dXJlcyB0aGF0IGFyZSBza2V3LCBsZXNzIHNrZXcuIFRoZSByZWNpcGUsIGNvbnRhaW5pbmcgdGhlc2UgcHJlcHJvY2Vzc2luZyBzdGVwcywgd2FzIHByZXBhcmVkIG9uIHRoZSB0cmFpbiBzZXQgYW5kIHRoZW4gYmFrZWQgb24gdGhlIHRyYWluIHNldCBhcyB3ZWxsIGFzIG9uIHRoZSB0ZXN0IHNldC4gTm8gbm9ybWFsaXphdGlvbiB3YXMgbmVlZGVkIGZvciB0aGUgbWFjaGluZSBsZWFybmluZyBtb2RlbHMgdGhhdCB3ZXJlIHRyYWluZWQgaW4gdGhpcyByZXBvcnQuIFRoZSByZWNpcGUgY2FuIGJlIGZvdW5kIGluIEFwcGVuZGl4IDYuMS4KCiMjIE1vZGVsIHRyYWluaW5nCgpUaGlzIHNlY3Rpb24gd2lsbCBkaXZlIGRlZXBlciBpbnRvIHRoZSB0cmFpbmVkIG1vZGVscy4gVGhlIG1vZGVscyB3ZXJlIHRyYWluZWQgdXNpbmcgdGhlIHNtYWxsZXIgdHJhaW4gc2V0LiBTZWUgQXBwZW5kaXggNi4yLTYuNSBmb3IgdGhlIGNvZGUgb2YgdGhlIG1vZGVscy4KCkNyb3NzLXZhbGlkYXRpb24gd2FzIHBlcmZvcm1lZCBiZXNpZGVzIHVzaW5nIGEgc2VwYXJhdGUgdGVzdCBzZXQgZm9yIG1vZGVsIGFzc2Vzc21lbnQuIFdoZXJlIGFwcGxpY2FibGUsIHRoZSBvbmUgc3RhbmRhcmQgZXJyb3IgcnVsZSBpcyBhcHBsaWVkIHRvIHNlbGVjdCB0aGUgdmFsdWUgb2YgdGhlIHR1bmluZyBwYXJhbWV0ZXIuIFRvIHByb3ZpZGUgYW4gb3ZlcnZpZXcsIHRoZSBmb2xsb3dpbmcgc2V0dGluZ3Mgd2VyZSB1c2VkIHRvIHRyYWluIHRoZSBtb2RlbHM6Cgp8ICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgKipSZXNhbXBsaW5nIG1ldGhvZCoqIHwgQ3Jvc3MtdmFsaWRhdGlvbiAgICAgICAgfAp8ICoqTnVtYmVyIG9mIGZvbGRzKiogICB8IDEwICAgICAgICAgICAgICAgICAgICAgIHwKfCAqKlNlbGVjdGlvbiBtZXRob2QqKiAgfCBPbmUgc3RhbmRhcmQgZXJyb3IgcnVsZSB8CnwgKipNZXRyaWMqKiAgICAgICAgICAgIHwgQVVDICAgICAgICAgICAgICAgICAgICAgfAoKYGBge3IgaW5jbHVkZT1GQUxTRX0KY3RybCA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgCiAgICAgICAgICAgICAgICAgICAgIG51bWJlciA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uRnVuY3Rpb24gPSAib25lU0UiLCAKICAgICAgICAgICAgICAgICAgICAgY2xhc3NQcm9icyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5RnVuY3Rpb24gPSB0d29DbGFzc1N1bW1hcnkpCmBgYAoKKipCYWNrd2FyZCBzdGVwd2lzZSByZWdyZXNzaW9uKioKCkEgZ2xtIG1vZGVsIHdpdGggYmFja3dhcmQgc3RlcHdpc2UgZmVhdHVyZSBzZWxlY3Rpb24gd2FzIHRyYWluZWQsIHVzaW5nIDEwLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbi4gVGhlIEFJQyBpbmRpY2F0ZWQgd2hpY2ggcHJlZGljdG9ycyBtYWtlIHRoZSBtb2RlbCBtb3JlIGNvbXBsaWNhdGVkLiBUaGUgZmluYWwgbW9kZWwgcmVzdWx0aW5nIGZyb20gdGhpcyB0cmFpbmluZyBoYWQgYSBST0Mgb2YgMC44OTEuIFRoZSAxMCBtb3N0IGltcG9ydGFudCB2YXJpYWJsZXMgYWNjb3JkaW5nIHRvIHRoaXMgbW9kZWwgY2FuIGJlIHNlZW4gYmVsb3cuCgpgYGB7ciBlY2hvPUZBTFNFfQp2YXJJbXAoc3RlcF9nbG0kZmluYWxNb2RlbCkgJT4lIGFycmFuZ2UoZGVzYyhPdmVyYWxsKSkgJT4lIGhlYWQoMTApICU+JSBrYWJsZSgpICU+JSBrYWJsZV9zdHlsaW5nKCkgCmBgYAoKVGhpcyBzaG93cyB0aGF0IHRoZSBtb3N0IGltcG9ydGFudCBwcmVkaWN0b3IgZm9yIHdoZXRoZXIgYSBib29raW5nIHdpbGwgYmUgY2FuY2VsZWQgb3Igbm90LCBpcyB0aGUgbnVtYmVyIG9mIHNwZWNpYWwgcmVxdWVzdHMuIFRoZSBsZWFkIHRpbWUgaXMgYWxzbyBhIGdvb2QgcHJlZGljdG9yLCBhcyBjb3VsZCBhbHNvIGJlIHNlZW4gZWFybGllciBkdXJpbmcgZGF0YSBleHBsb3JhdGlvbi4gTW9yZW92ZXIsIHRoZSBjb3VudHJpZXMgUG9ydHVnYWwsIEl0YWx5IGFuZCBDaGluYSBhbHNvIHNlZW0gdG8gYmUgZ29vZCBwcmVkaWN0b3JzIGZvciBgaXNfY2FuY2VsbGVkYC4KCioqTGFzc28gcmVncmVzc2lvbioqCgpOZXh0LCBhIGxhc3NvIHJlZ3Jlc3Npb24gd2FzIHRyYWluZWQsIGFsc28gdXNpbmcgMTAtZm9sZCBjcm9zcyB2YWxpZGF0aW9uLiBUaGlzIG1vZGVsIGlzIGFsc28gYWJsZSB0byBpZGVudGlmeSAoaXIpcmVsZXZhbnQgdmFyaWFibGVzIGJ5IHNocmlua2luZyB0aG9zZSB0aGF0IGRvbid0IGhhdmUgYSBsb3Qgb2YgaW5mbHVlbmNlIG9uIGBpc19jYW5jZWxsZWRgIHRvd2FyZHMgMC4gVGhlIG9wdGltYWwgbW9kZWwgd2FzIHNlbGVjdGVkIHVzaW5nIHRoZSBvbmUgU0UgcnVsZSBhbmQgaGFkIGEgbGFtYmRhIHZhbHVlIG9mIDAuMDAyMzM1NyBhbmQgUk9DIG9mIDAuODg5LiBUaGUgc2VsZWN0ZWQgdmFsdWUgb2YgbGFtYmRhIGNhbiBiZSBzZWVuIGluIHRoZSBmb2xsb3dpbmcgZ3JhcGggYXMgd2VsbDoKCmBgYHtyIGVjaG89RkFMU0V9CmdncGxvdChsYXNzbykgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGxhc3NvJGJlc3RUdW5lJGxhbWJkYSwgCiAgICAgICAgICAgICAgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gMikgKwogICBzY2FsZV94X2xvZzEwKCkKYGBgClRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzIG9mIHRoZSBmaW5hbCBtb2RlbHMgc2hvd2VkIHRoYXQgMTEgdmFyaWFibGVzIG91dCBvZiB0aGUgNTMgd2VyZSBzZXQgdG8gMC4gTW9udGhzIHN1Y2ggYXMgTWFyY2gsIE9jdG9iZXIgYW5kIE5vdmVtYmVyIHdlcmUgcmVtb3ZlZC4gUmVhc29uIGZvciB0aGF0IGNvdWxkIGJlIGJlY2F1c2UgdGhlc2UgbW9udGhzIGZhbGwgaW4gdGhlIGxvdyBzZWFzb24gb2YgdGhlIGhvdGVsIGluZHVzdHJ5LiBXaGVuIGxvb2tpbmcgYXQgdGhlIGltcG9ydGFuY2Ugb2YgdmFyaWFibGVzLCBhIGZldyBjb25jbHVzaW9ucyBjYW4gYmUgbWFkZS4gSW4gdGhpcyBtb2RlbCwgdGhlIGRlcG9zaXQgdHlwZSBOb24tcmVmdW5kIGlzIHRoZSBtb3N0IGltcG9ydGFudCBwcmVkaWN0b3IuIFRoaXMgcHJlZGljdG9yIHdhcyBhbHNvIGluIHRoZSB0b3AgNSBvZiBtb3N0IGltcG9ydGFudCB2YXJpYWJsZXMgaW4gdGhlIGJhY2t3YXJkIHN0ZXB3aXNlIHJlZ3Jlc3Npb24uIEZ1cnRoZXJtb3JlLCB0aGUgdG90YWwgbnVtYmVyIG9mIHNwZWNpYWwgcmVxdWVzdHMsIFBvcnR1Z2FsLCBDaGluYSwgcHJldmlvdXMgY2FuY2VsbGF0aW9ucyBhbmQgdGhlIG9ubGluZSB0cmF2ZWwgYWdlbnQgbWFya2V0IHNlZ21lbnQgYXJlIGNvbnNpZGVyZWQgaW1wb3J0YW50IGluIGJvdGggbW9kZWxzIHdoZW4gY29tcGFyaW5nIHRoZW0gaW4gdGVybXMgb2YgdmFyaWFibGUgaW1wb3J0YW5jZS4gQXMgc3VjaCwgdGhlcmUgYXJlIGEgZ29vZCBudW1iZXIgb2YgcHJlZGljdG9ycyBvbiB3aGljaCBib3RoIG1vZGVscyBhZ3JlZSB0aGF0IHRoZXkgYXJlIHJlbGV2YW50IGluIHByZWRpY3RpbmcgaG90ZWwgYm9va2luZ3MgY2FuY2VsbGF0aW9ucy4KCmBgYHtyIGVjaG89RkFMU0V9CnZhckltcChsYXNzbyRmaW5hbE1vZGVsKSAlPiUgYXJyYW5nZShkZXNjKE92ZXJhbGwpKSAlPiUgaGVhZCgxMCkgJT4lIGthYmxlKCkgJT4lIGthYmxlX3N0eWxpbmcoKSAKYGBgCgoqKkRlY2lzaW9uIHRyZWUqKgoKQSBkZWNpc2lvbiB0cmVlIHdhcyBidWlsZCBhbmQgdHJhaW5lZCB1c2luZyAxMC1mb2xkIGNyb3NzIHZhbGlkYXRpb24uIFRoZSBzZWxlY3RlZCBtb2RlbCBoYWQgYSB2YWx1ZSBvZiAwLjAwMzcyNiBmb3IgY3Agd2l0aCBhIFJPQyBvZiAwLjg3NS4gUHJ1bmluZyB3YXMgcGVyZm9ybWVkIHVzaW5nIHRoZSBvbmUgc3RhbmRhcmQgZXJyb3IgcnVsZS4gVGhlIGRlY2lzaW9uIHRyZWUgbG9va3MgYXMgZm9sbG93czoKCmBgYHtyIGVjaG89RkFMU0V9CnBycChkX3RyZWUkZmluYWxNb2RlbCkKYGBgCgpUaGUgdmFyaWFibGUgaW1wb3J0YW5jZSBpbiB0aGlzIG1vZGVsIGNhbiBiZSBzZWVuIGluIHRoZSB0YWJsZSBiZWxvdy4gQWdhaW4sIGNvbnNpc3RlbnQgd2l0aCBwcmV2aW91cyBtb2RlbHMgYGRlcG9zaXRfdHlwZV9Ob24uUmVmdW5kYCwgYHRvdGFsX29mX3NwZWNpYWxfcmVxdWVzdHNgLCBgY291bnRyeV9QUlRgLCBgbGVhZF90aW1lYCwgYHByZXZpb3VzX2NhbmNlbGxhdGlvbnNgLCBgbWFya2V0X3NlZ21lbnRfT25saW5lLlRBYCBhbmQgYGN1c3RvbWVyX3R5cGVfVHJhbnNpZW50LlBhcnR5YCBzZWVtIHRvIGJlIGltcG9ydGFudCBwcmVkaWN0b3JzLgoKYGBge3IgZWNobz1GQUxTRX0KdmFySW1wKGRfdHJlZSRmaW5hbE1vZGVsKSAlPiUgYXJyYW5nZShkZXNjKE92ZXJhbGwpKSAlPiUgaGVhZCgxMCkgJT4lIGthYmxlKCkgJT4lIGthYmxlX3N0eWxpbmcoKSAKYGBgCgoqKkJvb3N0ZWQgY2xhc3NpZmljYXRpb24gdHJlZSoqCgpMYXN0bHksIGEgYm9vc3RlZCBjbGFzc2lmaWNhdGlvbiB0cmVlIHdhcyB0cmFpbmVkIHVzaW5nIDEwLWZvbGQgY3Jvc3MgdmFsaWRhdGlvbi4gVGhlIHR1bmluZyBncmlkIHRvIHRyYWluIHRoZSBtb2RlbCB3YXMgYXMgZm9sbG93czoKCnwgVHVuaW5nIHBhcmFtZXRlcnMgICAgIHwgIFZhbHVlcyAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCBCb29zdGluZyBpdGVyYXRpb25zICAgfCAxMDAwLCAyNTAwLCAzMDAwICAgICAgICB8CnwgSW50ZXJhY3Rpb24gZGVwdGggICAgIHwgMSwgMiwgMyAgICAgICAgICAgICAgICAgfAp8IFNocmlua2FnZSAgICAgICAgICAgICB8IDAuMDEsIDAuMSAgICAgICAgICAgICAgIHwKCkEgc3VtbWFyeSBvZiB0aGUgdHJhaW5pbmcgcmVzdWx0cyBjYW4gYmUgc2VlbiBiZWxvdzoKCmBgYHtyIGVjaG89RkFMU0V9CnBsb3QoeGdiKQpgYGAKClRoZSBmaW5hbCBtb2RlbCB0aGF0IHdhcyBldmVudHVhbGx5IHNlbGVjdGVkIGJhc2VkIG9uIHRoZSBvbmUgU0UgcnVsZSBoYXMgMTAwMCBib29zdGluZyBpdGVyYXRpb25zLCBhbiBpbnRlcmFjdGlvbiBkZXB0aCBvZiAzLCBhbmQgYSBzaHJpbmthZ2UgcGFyYW1ldGVyIG9mIDAuMDEuIFRoZSBjb3JyZXNwb25kaW5nIFJPQyBpcyAwLjkxMTgzOTcuIE9uZSB0cmVlIGluIHRoaXMgbW9kZWwgaXMgc2hvd2VkIGJlbG93LiBGcm9tIHRoZSBwbG90LCB3ZSBjYW4gc2VlIHRoYXQgZGVwb3NpdCB0eXBlIE5vbi1yZWZ1bmQgaXMgdXNlZCB0byBtYWtlIHRoZSBmaXJzdCBzcGxpdCBpbiB0aGUgdHJlZS4KCmBgYHtyIGVjaG89RkFMU0V9CnhnYi5wbG90LnRyZWUobW9kZWwgPSB4Z2IkZmluYWxNb2RlbCwgdHJlZXMgPSAxKQpgYGAKCiMjIE1vZGVsIHBlcmZvcm1hbmNlCgpJbiB0aGlzIHNlY3Rpb24sIGFuIGFzc2Vzc21lbnQgaXMgZG9uZSBvbiBob3cgd2VsbCB0aGUgbW9kZWxzIGFyZSBhYmxlIHRvIHByZWRpY3Qgb24gdGhlIHNtYWxsZXIgdGVzdCBzZXQgdGhhdCB3YXMgY3JlYXRlZCBpbiBhbiBlYXJsaWVyIHN0YWdlLiBBZnRlciBtYWtpbmcgdGhlIHByZWRpY3Rpb25zLCBjb25mdXNpb24gbWF0cmljZXMgd2VyZSBjcmVhdGVkIGZvciBlYWNoIG1vZGVsIHRvIHNlZSBob3cgdGhleSBwZXJmb3JtLiBUaGUgZGVjaXNpb24gdGhyZXNob2xkIHdhcyBzZXQgdG8gMC40MiwgYXMgdG8gY2FsY3VsYXRlIHRoZSBjb3JyZWN0IEFjY3VyYWN5LiBVc2luZyB0aGUgZGVmYXVsdCB3aWxsIHJlc3VsdCBpbiBhIGhpZ2hlciBBY2N1cmFjeSwgYnV0IHRoZSBtb2RlbHMgd2lsbCBiZSBiaWFzZWQgdG93YXJkcyB0aGUgbWFqb3JpdHkgY2xhc3MuIFRoaXMgY2FuIGxlYWQgdG8gZXJyb25lb3VzIGNvbmNsdXNpb25zIGFib3V0IHRoZSBwcmVkaWN0aW9ucyBtYWRlLiBQbGVhc2UgZmluZCBiZWxvdyB0aGUgcGVyZm9ybWFuY2UgbWV0cmljcyBmb3IgZWFjaCBtb2RlbC4KCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmNvbmZ1c2lvbl9tYXRyaXggPC0gZnVuY3Rpb24oYWN0dWFsLCBwcmVkaWN0aW9ucywgdGhyZXNob2xkKSB7CiBjbGFzc2VzIDwtIGN1dChwcmVkaWN0aW9ucywgCiAgICAgICAgICAgICAgICBicmVha3MgPSBjKC1JbmYsIHRocmVzaG9sZCwgSW5mKSwgCiAgICAgICAgICAgICAgICBsYWJlbHMgPSBsZXZlbHMoYWN0dWFsKSkKIHJlcyA8LSB0YWJsZShBY3R1YWwgPSBhY3R1YWwsIFByZWRpY3Rpb24gPSBjbGFzc2VzKQogcmVzCn0KYGBgCiAgICAgICAgICAgICAgICAgICAgICAgICAgCmBgYHtyIGluY2x1ZGU9RkFMU0V9CnN0ZXBfcHJlZHMgPC0gcHJlZGljdChzdGVwX2dsbSwgbmV3ZGF0YSA9IGJvb2tpbmdzX3Rlc3RfYmFrZWQsIHR5cGUgPSAicHJvYiIpCgpzdGVwX2NtIDwtIGNvbmZ1c2lvbl9tYXRyaXgoYWN0dWFsID0gYm9va2luZ3NfdGVzdF9iYWtlZCRpc19jYW5jZWxsZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdGlvbnMgPSBzdGVwX3ByZWRzJHllcywgdGhyZXNob2xkID0gMC40MikKCmNvbmZ1c2lvbk1hdHJpeChzdGVwX2NtLCBwb3NpdGl2ZSA9ICJ5ZXMiLCBtb2RlID0gImV2ZXJ5dGhpbmciKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9Cmxhc3NvX3ByZWRzIDwtIHByZWRpY3QobGFzc28sIG5ld2RhdGEgPSBib29raW5nc190ZXN0X2Jha2VkLCB0eXBlID0gInByb2IiKQoKbGFzc29fY20gPC0gY29uZnVzaW9uX21hdHJpeChhY3R1YWwgPSBib29raW5nc190ZXN0X2Jha2VkJGlzX2NhbmNlbGxlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVkaWN0aW9ucyA9IGxhc3NvX3ByZWRzJHllcywgdGhyZXNob2xkID0gMC40MikKCmNvbmZ1c2lvbk1hdHJpeChsYXNzb19jbSwgcG9zaXRpdmUgPSAieWVzIiwgbW9kZSA9ICJldmVyeXRoaW5nIikKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpkX3RyZWVfcHJlZHMgPC0gcHJlZGljdChkX3RyZWUsIG5ld2RhdGEgPSBib29raW5nc190ZXN0X2Jha2VkLCB0eXBlID0gInByb2IiKQoKZF90cmVlX2NtIDwtIGNvbmZ1c2lvbl9tYXRyaXgoYWN0dWFsID0gYm9va2luZ3NfdGVzdF9iYWtlZCRpc19jYW5jZWxsZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdGlvbnMgPSBkX3RyZWVfcHJlZHMkeWVzLCB0aHJlc2hvbGQgPSAwLjQyKQoKY29uZnVzaW9uTWF0cml4KGRfdHJlZV9jbSwgcG9zaXRpdmUgPSAieWVzIiwgbW9kZSA9ICJldmVyeXRoaW5nIikKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQp4Z2JfcHJlZHMgPC0gcHJlZGljdCh4Z2IsIG5ld2RhdGEgPSBib29raW5nc190ZXN0X2Jha2VkLCB0eXBlID0gInByb2IiKQoKeGdiX2NtIDwtIGNvbmZ1c2lvbl9tYXRyaXgoYWN0dWFsID0gYm9va2luZ3NfdGVzdF9iYWtlZCRpc19jYW5jZWxsZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdGlvbnMgPSB4Z2JfcHJlZHMkeWVzLCB0aHJlc2hvbGQgPSAwLjQyKQoKY29uZnVzaW9uTWF0cml4KHhnYl9jbSwgcG9zaXRpdmUgPSAieWVzIiwgbW9kZSA9ICJldmVyeXRoaW5nIikKYGBgCgoqKk92ZXJ2aWV3IG9mIG1vZGVsIHBlcmZvcm1hbmNlKioKCnx8IEJhY2t3YXJkIHN0ZXB3aXNlIHJlZ3Jlc3Npb24gfCBMYXNzbyByZWdyZXNzaW9uIHwgRGVjaXNpb24gdHJlZSB8IEJvb3N0ZWQgY2xhc3NpZmljYXRpb24gdHJlZSB8CnwtLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLXwKfCBBY2N1cmFjeSAgICAgICAgIHwgMC44MTM3ICAgICAgICAgICAgIHwgMC44MTA1ICAgICAgICAgIHwgMC44MjcyICAgICAgICAgICB8IDAuODUyMyAgICAgICAgICAgfAp8IENvaGVuJ3Mga2FwcGEgICAgfCAwLjYwNzYgICAgICAgICAgICAgfCAwLjYwODEgICAgICAgICAgfCAwLjYzODUgICAgICAgICAgIHwgMC42OTcxICAgICAgICAgICB8CnwgU2Vuc2l0aXZpdHkgICAgICB8IDAuODMxNSAgICAgICAgICAgICB8IDAuNzg0MiAgICAgICAgICB8IDAuODMzMyAgICAgICAgICAgfCAwLjgxNjggICAgICAgICAgIHwKfCBTcGVjaWZpY2l0eSAgICAgIHwgMC44MDQxICAgICAgICAgICAgIHwgMC43NTMxICAgICAgICAgIHwgMC44MjM3ICAgICAgICAgICB8IDAuODc4NiAgICAgICAgICAgfAp8IFByZWNpc2lvbiAgICAgICAgfCAwLjY5NDEgICAgICAgICAgICAgfCAwLjc1MzEgICAgICAgICAgfCAwLjczMjQgICAgICAgICAgIHwgMC44MzI4ICAgICAgICAgICB8CnwgUmVjYWxsICAgICAgICAgICB8IDAuODMxNSAgICAgICAgICAgICB8IDAuNzg0MiAgICAgICAgICB8IDAuODMzMyAgICAgICAgICAgfCAwLjgxNjggICAgICAgICAgIHwKfCBGMSAgICAgICAgICAgICAgIHwgMC43NTY2ICAgICAgICAgICAgIHwgMC43NjgzICAgICAgICAgIHwgMC43Nzk2ICAgICAgICAgICB8IDAuODI0NyAgICAgICAgICAgfAoKQmFzZWQgb24gdGhlIEFjY3VyYWN5LCB0aGUgYm9vc3RlZCBjbGFzc2lmaWNhdGlvbiB0cmVlIHNlZW1zIHRvIHBlcmZvcm0gdGhlIGJlc3QsIGZvbGxvd2VkIGJ5IHRoZSBkZWNpc2lvbiB0cmVlLiBUaGUgYmFja3dhcmQgc3RlcHdpc2UgcmVncmVzc2lvbiBjb21lcyBjbG9zZSBiZWhpbmQsIHdoaWxzdCB0aGUgbGFzc28gcmVncmVzc2lvbiBoYXMgdGhlIGxvd2VzdCBBY2N1cmFjeS4gVGhlIG90aGVyIG1ldHJpY3MgYWxzbyBnaXZlIGEgZ29vZCBpbmRpY2F0aW9uIG9mIGhvdyB3ZWxsIHRoZSBtb2RlbHMgcGVyZm9ybS4gIFRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgbW9kZWxzIHdpbGwgYmUgdmlzdWFsaXplZCB0byBnZXQgYSBiZXR0ZXIgaWRlYSB3aGljaCBtb2RlbCByZWFsbHkgcGVyZm9ybXMgdGhlIGJlc3QuCgoqKlJPQyBhbmQgQVVDKioKCldoZW4gcGxvdHRpbmcgdGhlIFJPQyBjdXJ2ZXMgZm9yIHRoZSBtb2RlbHMsIGl0IGJlY29tZXMgbW9yZSBjbGVhciB0aGF0IHRoZSBncmFkaWVudCBib29zdGluZyBtb2RlbCBpbmRlZWQgcGVyZm9ybXMgdGhlIGJlc3QgYXMgaXRzIGN1cnZlIGxpZXMgYWJvdmUgYWxsIG90aGVycy4gVGhlIGRlY2lzaW9uIHRyZWUgc2VlbXMgdG8gaGF2ZSBhIHJhbmdlIHdoZXJlIGl0IHBlcmZvcm1zIHdvcnNlIHRoYW4gYWxsIG90aGVyIG1vZGVscy4KCmBgYHtyIGVjaG89RkFMU0V9CnNvdXJjZSgiY2FsY19jb25mdXNpb24uUiIpCmNvbmZfZGYgPC0gY2FsY19jb25mdXNpb24oYWN0dWFsID0gYm9va2luZ3NfdGVzdF9iYWtlZCRpc19jYW5jZWxsZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpdmUgPSAieWVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcF9nbG0gPSBzdGVwX3ByZWRzJHllcywgbGFzc28gPSBsYXNzb19wcmVkcyR5ZXMsIGRfdHJlZSA9IGRfdHJlZV9wcmVkcyR5ZXMsIHhnYiA9IHhnYl9wcmVkcyR5ZXMpCgpjb25mX2RmIDwtIGNvbmZfZGYgJT4lIAogIG11dGF0ZShGUFIgPSBGUCAvIChUTiArIEZQKSwgVFBSID0gVFAgLyAoVFAgKyBGTikpCgpnZ3Bsb3QoY29uZl9kZiwgYWVzKHggPSBGUFIsIHkgPSBUUFIsIGNvbG91ciA9IE1vZGVsKSkgKwogIGdlb21fcGF0aCgpICsgCiAgZ2VvbV9hYmxpbmUoY29sb3VyID0gImdyZXkiLCBsaW5ldHlwZSA9IDIpICsgCiAgY29vcmRfZXF1YWwoKSAKYGBgCkJlbG93IGFyZSBhbHNvIHRoZSBBVUNzIG9mIHRoZSBtb2RlbHMuIFRoZSBib29zdGVkIGNsYXNzaWZpY2F0aW9uIHRyZWUgaGFzIGEgdmVyeSBnb29kIHNjb3JlIGFuZCBhbHNvIGhhcyB0aGUgaGlnaGVzdCBvbmUuIFRoZSBBVUMgb2YgdGhlIGxhc3NvIHJlZ3Jlc3Npb24gYW5kIGJhY2t3YXJkIHN0ZXB3aXNlIHJlZ3Jlc3Npb24gYXJlIHZlcnkgY2xvc2UgdG8gb25lIG90aGVyLCB3aGVyZWFzIHRoZSBkZWNpc2lvbiB0cmVlIGhhcyB0aGUgbG93ZXN0IEFVQyBvdXQgb2YgYWxsLiBUaHVzLCB0aGUgZGVjaXNpb24gdHJlZSBkb2Vzbid0IHBlcmZvcm0gYXMgZ29vZCBhcyB0aGUgb3RoZXIgbW9kZWxzIGJhc2VkIG9uIHRoZSBBVUMsIGFuZCBvcHBvc2VkIHRvIHdoYXQgdGhlIEFjY3VyYWN5IGluZGljYXRlZCBlYXJsaWVyLgoKYGBge3IgZWNobz1GQUxTRX0KY29uZl9kZiA8LSBjb25mX2RmICU+JSAKICBtdXRhdGUodHJhcF93aWR0aCA9IGxhZyhGUFIpIC0gRlBSLAogICAgICAgICB0cmFwX2hlaWdodCA9IDAuNSAqIChsYWcoVFBSKSArIFRQUiksCiAgICAgICAgIHRyYXBfYXJlYSA9IHRyYXBfd2lkdGggKiB0cmFwX2hlaWdodCkKCmNvbmZfZGYgJT4lIHN1bW1hcml6ZShBVUMgPSBzdW0odHJhcF9hcmVhLCBuYS5ybSA9IFRSVUUpKSAlPiUga2FibGUoKSAlPiUga2FibGVfc3R5bGluZygpCmBgYAoKKipDbGFzcyBzZXBhcmF0aW9uKioKCkluIHRoZSBmb2xsb3dpbmcgZmlndXJlcywgb25lIGNhbiBzZWUgdGhlIGNsYXNzIGRpc3RyaWJ1dGlvbnMgZm9yIGVhY2ggbW9kZWwuIEZyb20gdGhlc2UgZ3JhcGhzLCB0aGUgZ3JhZGllbnQgYm9vc3RpbmcgbW9kZWwsIGxhc3NvIHJlZ3Jlc3Npb24gYW5kIGJhY2t3YXJkIHN0ZXB3aXNlIHJlZ3Jlc3Npb24gc2VlbSB0byBkbyBhIGdvb2Qgam9iIGluIHNlcGFyYXRpbmcgdGhlIGNsYXNzZXMuIFRoZSBkZWNpc2lvbiB0cmVlIGhhcyBzb21lIG1vcmUgb3ZlcmxhcCBiZXR3ZWVuIHRoZSBjbGFzc2VzIGFuZCB0aHVzLCBtYXkgbm90IGJlIGFibGUgdG8gc2VwYXJhdGUgdGhlIGNsYXNzZXMgYXMgZ29vZCBhcyB0aGUgb3RoZXJzLiBUaGlzIGlzIGNvbnNpc3RlbnQgd2l0aCBvdXIgZm9ybWVyIG9ic2VydmF0aW9ucy4KCmBgYHtyIGVjaG89RkFMU0V9CnByZWRzIDwtIHRpYmJsZShBY3R1YWwgPSBib29raW5nc190ZXN0X2Jha2VkJGlzX2NhbmNlbGxlZCwKICAgICAgICAgICAgICAgIHN0ZXBfZ2xtID0gc3RlcF9wcmVkcyR5ZXMsIGxhc3NvID0gbGFzc29fcHJlZHMkeWVzLCBkX3RyZWUgPSBkX3RyZWVfcHJlZHMkeWVzLCB4Z2IgPSB4Z2JfcHJlZHMkeWVzKQpwcmVkcyA8LSBwcmVkcyAlPiUgIHBpdm90X2xvbmdlcihjb2xzID0gLUFjdHVhbCwgbmFtZXNfdG8gPSAiTW9kZWwiLCB2YWx1ZXNfdG8gPSAiUHJvYmFiaWxpdHkiKSAlPiUgCiAgYXJyYW5nZShNb2RlbCkKCmdncGxvdChwcmVkcywgYWVzKHggPSBQcm9iYWJpbGl0eSwgZmlsbCA9IEFjdHVhbCkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArIAogIGZhY2V0X3dyYXAofiBNb2RlbCwgc2NhbGVzID0gImZyZWVfeSIpCmBgYAoKKipDdW11bGF0aXZlIGdhaW4qKgoKVGhlIGZpZ3VyZSBiZWxvdyBzaG93cyB0aGUgY3VtdWxhdGl2ZSBnYWluIGNoYXJ0cyBmb3IgdGhlIG1vZGVscy4gVGhlIHVwcGVyIGRhc2hlZCBncmV5IGxpbmUgaXMgdGhlIGJlc3QgcG9zc2libGUgc2NlbmFyaW8sIGFuZCB3b3VsZCBtZWFuIHRoYXQgdGhlIGNsYXNzaWZpZXIgaXMgYWJsZSB0byByYW5rIHRoZSB0ZXN0IGNhc2VzIHBlcmZlY3RseS4gVGhlIGRhc2hlZCBncmV5IGxpbmUgdW5kZXJuZWF0aCBpcyB0aGUgd29yc3QgY2FzZSBzY2VuYXJpbywgYW5kIHdvdWxkIG1lYW4gdGhhdCB0aGUgY2xhc3NpZmllciByYW5rcyByYW5kb21ubHkuIFdoZW4gY29tcGFyaW5nIHRoZSBsaW5lcyBvZiB0aGUgbW9kZWxzLCB0aGUgYm9vc3RlZCBjbGFzc2lmaWNhdGlvbiB0cmVlIHBlcmZvcm1zIGJlc3Qgb25jZSBhZ2Fpbi4gVGhlIGxpbmVzIG9mIHRoZSBiYWNrd2FyZCBzdGVwd2lzZSByZWdyZXNzaW9uIGFuZCBsYXNzbyByZWdyZXNzaW9uIGFyZSBhbG1vc3QgaWRlbnRpY2FsLiAKCmBgYHtyIGVjaG89RkFMU0V9CmxpZnRfcHJlZHMgPC0gdGliYmxlKGlzX2NhbmNlbGxlZCA9IGJvb2tpbmdzX3Rlc3RfYmFrZWQkaXNfY2FuY2VsbGVkLAogICAgICAgICAgICAgICAgICAgICBzdGVwX2dsbSA9IHN0ZXBfcHJlZHMkeWVzLAogICAgICAgICAgICAgICAgICAgICBsYXNzbyA9IGxhc3NvX3ByZWRzJHllcywKICAgICAgICAgICAgICAgICAgICAgZF90cmVlID0gZF90cmVlX3ByZWRzJHllcywKICAgICAgICAgICAgICAgICAgICAgeGdiID0geGdiX3ByZWRzJHllcykKbW9kZWxzX2xpZnQgPC0gbGlmdChpc19jYW5jZWxsZWQgfiBzdGVwX2dsbSArIGxhc3NvICsgZF90cmVlICsgeGdiLCBkYXRhID0gbGlmdF9wcmVkcywKICAgICAgICAgICAgICAgICAgY2xhc3MgPSAieWVzIikKZ2dwbG90KG1vZGVsc19saWZ0KSArIGNvb3JkX2VxdWFsKCkKYGBgCgpJbiB0aGlzIHNlY3Rpb24sIHRoZSByZXN1bHRzIHNob3dlZCB0aGF0IHRoZSBib29zdGVkIGNsYXNzaWZpY2F0aW9uIHRyZWUgY2xlYXJseSBvdXRwZXJmb3JtcyB0aGUgb3RoZXIgbW9kZWxzLiBUaGVyZWZvcmUsIHRoaXMgbW9kZWwgd2FzIHNlbGVjdGVkIGZvciBldmFsdWF0aW9uIGluIHRoZSBmaW5hbCBwYXJ0IG9mIHRoZSByZXBvcnQuCgojIEZpbmFsIG1vZGVsCgpUaGUgaG90ZWwgb3duZXIgb2YgdGhlIFNlYXNpZGUgaG90ZWwgaGFzIHByb3ZpZGVkIGEgZmluYWwgdGVzdCBzZXQuIFRoaXMgc2VjdGlvbiB3aWxsIHJldmVhbCB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIHNlbGVjdGVkIG1vZGVsIG9uIHRoZSBwcmVkaWN0aW9ucyBmb3IgdGhpcyB0ZXN0IHNldC4gVGhlIGZpbmFsIG1vZGVsIHdhcyB0cmFpbmVkIG9uIHRoZSBlbnRpcmUgdHJhaW4gZGF0YSBzZXQgZmlyc3QgYmVmb3JlIG1ha2luZyB0aGUgcHJlZGljdGlvbnMgdXNpbmcgdGhlIHRyYWluZWQgbW9kZWwuIFRoZSBST0Mgb24gdGhlIGVudGlyZSB0cmFpbiBkYXRhIHNldCBpcyBub3cgMC45MTMuCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQp0dW5lR3JpZF94Z2JfZmluYWwgPC0gZXhwYW5kLmdyaWQoZXRhID0gYygwLjAxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtYXhfZGVwdGggPSAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHNhbXBsZV9ieXRyZWUgPSAwLjYsIAogICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2FtcGxlID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBucm91bmRzID0gYygxMDAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBnYW1tYSA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICBtaW5fY2hpbGRfd2VpZ2h0ID0gMSkKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpzZXQuc2VlZCgxNjAzKQpmaW5hbF94Z2IgPC0gdHJhaW4oaXNfY2FuY2VsbGVkIH4gLiwgCiAgICAgICAgICAgICBkYXRhID0gYm9va2luZ3NfZmluYWxfdHJhaW5fYmFrZWQsIAogICAgICAgICAgICAgbWV0aG9kID0gInhnYlRyZWUiLCAKICAgICAgICAgICAgIHRyQ29udHJvbCA9IGN0cmwsCiAgICAgICAgICAgICB0dW5lR3JpZCA9IHR1bmVHcmlkX3hnYl9maW5hbCwKICAgICAgICAgICAgIG1ldHJpYyA9ICJST0MiKQpmaW5hbF94Z2IKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpmaW5hbF9wcmVkcyA8LSBwcmVkaWN0KHhnYiwgbmV3ZGF0YSA9IGJvb2tpbmdzX2ZpbmFsX3Rlc3RfYmFrZWQsIHR5cGUgPSAicHJvYiIpCgpmaW5hbF9jbSA8LSBjb25mdXNpb25fbWF0cml4KGFjdHVhbCA9IGJvb2tpbmdzX2ZpbmFsX3Rlc3RfYmFrZWQkaXNfY2FuY2VsbGVkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWRpY3Rpb25zID0gZmluYWxfcHJlZHMkeWVzLCB0aHJlc2hvbGQgPSAwLjQyKQoKY29uZnVzaW9uTWF0cml4KGZpbmFsX2NtLCBwb3NpdGl2ZSA9ICJ5ZXMiLCBtb2RlID0gImV2ZXJ5dGhpbmciKQpgYGAKClRoZSB0YWJsZSBiZWxvdyBwcm92aWRlcyBhbiBvdmVydmlldyBvZiB0aGUgcGVyZm9ybWFuY2UgbWV0cmljcyBvZiB0aGUgZ3JhZGllbnQgYm9vc3RpbmcgbW9kZWwsIHdoaWNoIG1hZGUgcHJlZGljdGlvbnMgb24gdGhlIGZpbmFsIHRlc3Qgc2V0LiAKCnwgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCAqKkFjY3VyYWN5KiogICAgICAgICAgfCAwLjg1MDQgICAgICAgICAgICAgICAgICB8CnwgKipDb2hlbidzIGthcHBhKiogICAgIHwgMC42OTMxICAgICAgICAgICAgICAgICAgfAp8ICoqU2Vuc2l0aXZpdHkqKiAgICAgICB8IDAuODE1MCAgICAgICAgICAgICAgICAgIHwKfCAqKlNwZWNpZmljaXR5KiogICAgICAgfCAwLjg3NjYgICAgICAgICAgICAgICAgICB8CnwgKipQcmVjaXNpb24qKiAgICAgICAgIHwgMC44Mjk4ICAgICAgICAgICAgICAgICAgfAp8ICoqUmVjYWxsKiogICAgICAgICAgICB8IDAuODE1MCAgICAgICAgICAgICAgICAgIHwKfCAqKkYxKiogICAgICAgICAgICAgICAgfCAwLjgyMjMgICAgICAgICAgICAgICAgICB8CgpUaGUgZmluYWwgQWNjdXJhY3kgaXMgMC44NTA0LCB3aGljaCBpbmRpY2F0ZXMgdGhhdCB0aGUgbW9kZWwgcHJlZGljdGVkIHF1aXRlIHdlbGwgb24gdGhlIHRlc3Qgc2V0LiBPcHBvc2VkIHRvIEFjY3VyYWN5LCBhIGhpZ2ggRjEgc2NvcmUgaW5kaWNhdGVzIGxvdyBmYWxzZSBwb3NpdGl2ZXMgYW5kIG5lZ2F0aXZlcy4gSXQgaXMgdGhlcmVmb3JlIGFsc28gYSBtZWFzdXJlIG9mIGhvdyB3ZWxsIHRoZSBtb2RlbCBjYW4gY29ycmVjdGx5IGlkZW50aWZ5IHJlYWwgdGhyZWF0cywgYW5kIGlzIGluIHRoaXMgY2FzZSAtIHdpdGggYSB2YWx1ZSBvZiAwLjgyMiAtIGNvbnNpZGVyZWQgZ29vZC4gVGhlIHNlbnNpdGl2aXR5LXNwZWNpZmljaXR5IGFuZCBwcmVjaXNpb24tcmVjYWxsIGFsc28gcmVmbGVjdCBhIGdvb2QgcHJlZGljdGl2ZSBhYmlsaXR5IG9mIHRoZSBtb2RlbC4gVGFraW5nIHRoZSBBVUMgaW4gY29uc2lkZXJhdGlvbiBhcyB3ZWxsLCBpdCBhZ2FpbiBzaG93cyBhbiBleGNlbGxlbnQgc2NvcmUgZm9yIHRoZSBncmFkaWVudCBib29zdGluZyBtb2RlbDoKCmBgYHtyIGVjaG89RkFMU0V9CmZpbmFsX2NvbmZfZGYgPC0gY2FsY19jb25mdXNpb24oYWN0dWFsID0gYm9va2luZ3NfZmluYWxfdGVzdF9iYWtlZCRpc19jYW5jZWxsZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpdmUgPSAieWVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmluYWxfeGdiID0gZmluYWxfcHJlZHMkeWVzKQoKZmluYWxfY29uZl9kZiA8LSBmaW5hbF9jb25mX2RmICU+JSAKICBtdXRhdGUoRlBSID0gRlAgLyAoVE4gKyBGUCksIFRQUiA9IFRQIC8gKFRQICsgRk4pKQoKZmluYWxfY29uZl9kZiA8LSBmaW5hbF9jb25mX2RmICU+JSAKICBtdXRhdGUodHJhcF93aWR0aCA9IGxhZyhGUFIpIC0gRlBSLAogICAgICAgICB0cmFwX2hlaWdodCA9IDAuNSAqIChsYWcoVFBSKSArIFRQUiksCiAgICAgICAgIHRyYXBfYXJlYSA9IHRyYXBfd2lkdGggKiB0cmFwX2hlaWdodCkKCmZpbmFsX2NvbmZfZGYgJT4lIHN1bW1hcml6ZShBVUMgPSBzdW0odHJhcF9hcmVhLCBuYS5ybSA9IFRSVUUpKSAlPiUga2FibGUoKSAlPiUga2FibGVfc3R5bGluZygpCmBgYApBcyBzZWVuIGluIHRoZSBmaWd1cmUgYmVsb3csIHRoZXJlIGlzIGEgY2xlYXIgZGlzdGluY3Rpb24gYmV0d2VlbiB0aGUgY2xhc3Nlcy4gSXQgY2FuIHRoZXJlZm9yZSBiZSBjb25jbHVkZWQgdGhhdCB0aGlzIG1vZGVsIGlzIGFibGUgdG8gc2VwYXJhdGUgdGhlIGNsYXNzZXMgd2VsbC4gCgpgYGB7ciBlY2hvPUZBTFNFfQpmaW5hbF9wcmVkczIgPC0gdGliYmxlKEFjdHVhbCA9IGJvb2tpbmdzX2ZpbmFsX3Rlc3RfYmFrZWQkaXNfY2FuY2VsbGVkLAogICAgICAgICAgICAgICAgZmluYWxfeGdiID0gZmluYWxfcHJlZHMkeWVzKQpmaW5hbF9wcmVkczIgPC0gZmluYWxfcHJlZHMyICU+JSAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtQWN0dWFsLCBuYW1lc190byA9ICJNb2RlbCIsIHZhbHVlc190byA9ICJQcm9iYWJpbGl0eSIpICU+JSAKICBhcnJhbmdlKE1vZGVsKQoKZ2dwbG90KGZpbmFsX3ByZWRzMiwgYWVzKHggPSBQcm9iYWJpbGl0eSwgZmlsbCA9IEFjdHVhbCkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArIAogIGZhY2V0X3dyYXAofiBNb2RlbCwgc2NhbGVzID0gImZyZWVfeSIpCmBgYAoKQmVsb3cgaXMgdGhlIGN1bXVsYXRpdmUgZ2FpbiBjaGFydCBmb3IgdGhlIGdyYWRpZW50IGJvb3N0aW5nIG1vZGVsIG9uIHRoZSBmaW5hbCB0ZXN0IHNldC4gVGhpcyBncmFwaCBzaG93cyB0aGF0IHRoZSBtb2RlbCBjYW4gaWRlbnRpZnkgYWJvdXQgNjAlIG9mIHRoZSBjYW5jZWxsYXRpb25zIHdpdGgganVzdCAyNSUgb2YgdGhlIHRlc3Qgc2V0LgoKYGBge3IgZWNobz1GQUxTRX0KbGlmdF9maW5hbF9wcmVkcyA8LSB0aWJibGUoaXNfY2FuY2VsbGVkID0gYm9va2luZ3NfZmluYWxfdGVzdF9iYWtlZCRpc19jYW5jZWxsZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb2JhYmlsaXRpZXMgPSBmaW5hbF9wcmVkcyR5ZXMpCmxpZnRfZmluYWwgPC0gbGlmdChpc19jYW5jZWxsZWQgfiBQcm9iYWJpbGl0aWVzLCBkYXRhID0gbGlmdF9maW5hbF9wcmVkcywKICAgICAgICAgICAgICAgICAgY2xhc3MgPSAieWVzIikKZ2dwbG90KGxpZnRfZmluYWwpICsgY29vcmRfZXF1YWwoKQpgYGAKCiMgQ29uY2x1c2lvbgoKVGhpcyByZXBvcnQgbG9va2VkIGF0IHN1YnNldCBzZWxlY3Rpb24tLCByZWd1bGFyaXphdGlvbi0sIGRlY2lzaW9uIHRyZWUtIGFuZCBlbnNlbWJsZSBtZXRob2RzIHRvIGJ1aWxkIGEgcHJlZGljdGl2ZSBtb2RlbCBmb3IgdGhlIFNlYXNpZGUgSG90ZWwsIGFzIGEgbWVhbnMgdG8gZm9yZWNhc3QgYm9va2luZyBjYW5jZWxsYXRpb25zLiAKCkFmdGVyIHRyYWluaW5nIHNldmVyYWwgZGlmZmVyZW50IG1vZGVscyBvbiB0aGUgdHJhaW4gc2V0IGFuZCBjb21wYXJpbmcgdGhlaXIgcGVyZm9ybWFuY2UsIGl0IGNhbiBiZSBjb25jbHVkZWQgdGhhdCB0aGUgZ3JhZGllbnQgYm9vc3RpbmcgbW9kZWwgcGVyZm9ybWVkIGJlc3Qgb3V0IG9mIGFsbC4gVGhlcmVmb3JlLCB0aGlzIG1vZGVsIHdhcyBzZWxlY3RlZCB0byBwcmVkaWN0IHRoZSB0ZXN0IHNldC4gRm9yIHRoaXMgbW9kZWwsIFllby1Kb2huc29uIHRyYW5zZm9ybWF0aW9ucyB3ZXJlIHBlcmZvcm1lZCBvbiB0aGUgcHJlZGljdG9ycywgYW5kIHRoZSB0b3RhbCBudW1iZXIgb2YgY2F0ZWdvcmllcyB3ZXJlIHJlZHVjZWQgdG8gYSBncmVhdCBleHRlbnQuIDEwIGZvbGQgY3Jvc3MtdmFsaWRhdGlvbiB3YXMgdXNlZCBvbiB0aGUgdHJhaW4gc2V0IHRvIGZpbmQgdGhlIG9wdGltYWwgdHVuaW5nIHBhcmFtZXRlcnMsIGFuZCB0aGUgb25lIHN0YW5kYXJkIGVycm9yIHJ1bGUgd2FzIGFwcGxpZWQgdG8gZmluZCBhIHNpbXBsZXIgbW9kZWwgd2hpY2ggaXMgbm90IHNpZ25pZmljYW50bHkgd29yc2UgdGhhbiB0aGUgYWJzb2x1dGUgYmVzdC4gRXZlbnR1YWxseSwgdGhlIGZpbmFsIGdyYWRpZW50IGJvb3N0aW5nIG1vZGVsIGhhZCAxMDAwIGl0ZXJhdGlvbnMsIGFuIGludGVyYWN0aW9uIGRlcHRoIG9mIDMgYW5kIGEgc2hyaW5rYWdlIHZhbHVlIG9mIDAuMDEuIFRoZSByZXN1bHRzIGluZGljYXRlZCBhIGdvb2QgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZSBvZiB0aGUgbW9kZWwuCgpFbnNlbWJsZXMgc3VjaCBhcyBib29zdGluZyBtb2RlbHMgYXJlIHVzdWFsbHkgY29uc2lkZXJlZCBoaWdobHkgYWNjdXJhdGUgY29tcGFyZWQgdG8gZm9yIGV4YW1wbGUgZGVjaXNpb24gdHJlZXMsIHdoaWNoIGFyZSBwcm9uZSB0byBvdmVyZml0dGluZy4gVGhpcyBjYW4gZXhwbGFpbiB0aGUgZ29vZCBwZXJmb3JtYW5jZSBvZiB0aGUgZ3JhZGllbnQgYm9vc3RpbmcgbW9kZWwuIFRoZSBjb3N0IG9mIHRoaXMgbW9kZWwgaXMgdGhlIGxpbWl0ZWQgaW50ZXJwcmV0YWJpbGl0eS4gVGhlIG90aGVyIHRocmVlIG1vZGVscyB0aGF0IHdlcmUgYXNzZXNzZWQgaW4gdGhpcyByZXBvcnQgYXJlIGluIHN1Y2ggY2FzZSBiZXR0ZXIuIEdvb2QgaW50ZXJwcmV0YWJpbGl0eSBjYW4gcHJvdmlkZSBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIHRoZSBmZWF0dXJlcyB0aGF0IG1heSBvciBtYXkgbm90IGJlIGdvb2QgcHJlZGljdG9ycyBvZiBgaXNfY2FuY2VsbGVkYC4gQmVjYXVzZSBvZiB0aGlzLCB0aGUgdGhyZWUgcmVzcGVjdGl2ZSBtb2RlbHMgd2VyZSBhYmxlIHRvIGdpdmUgbW9yZSBpbnNpZ2h0IGludG8gdGhlIHBvdGVudGlhbCBkcml2ZXJzIG9mIGhvdGVsIGNhbmNlbGxhdGlvbnMuIE9uZSBvZiB0aGVtIGlzIGZvciBleGFtcGxlIHRoZSBsZWFkIHRpbWUgYmV0d2VlbiB0aGUgYm9va2luZyBkYXRlIGFuZCB0aGUgYXJyaXZhbCBkYXRlLiBCb29raW5ncyB0aGF0IGFyZSBndWFyYW50ZWVkIHdpdGggYSBmdWxsIGRlcG9zaXQgKE5vbi1yZWZ1bmQpIGNhbiBnaXZlIGFuIGVhcmx5IGluZGljYXRpb24gb2Ygd2hldGhlciBhIGJvb2tpbmcgd2lsbCBiZSBjYW5jZWxlZCBvciBub3QuIEZ1cnRoZXJtb3JlLCBib29raW5ncyBtYWRlIHRocm91Z2ggYW4gb25saW5lIHRyYXZlbCBhZ2VudCBhbHNvIHNlZW1lZCB0byBiZSBhIGdvb2QgcHJlZGljdG9yIGZvciBib29raW5nIGNhbmNlbGxhdGlvbnMuIFRoZSBzYW1lIGdvZXMgZm9yIHByZXZpb3VzIGNhbmNlbGxhdGlvbnMgYW5kIHRoZSBudW1iZXIgb2Ygc3BlY2lhbCByZXF1ZXN0cy4gVGhlc2UgaW5zaWdodHMgY2FuIGhlbHAgdGhlIGhvdGVsIGZ1cnRoZXIgaW4gdGhlaXIgbWFya2V0aW5nIGVmZm9ydHMuIEZvciBleGFtcGxlLCBieSBwcm92aWRpbmcgb2ZmZXJzIHRvIHRob3NlIHRoYXQgYXJlIGxpa2VseSB0byBjYW5jZWwuCgpXaGVuIGl0IGNvbWVzIHRvIHN0YWZmIGFuZCBpbnZlbnRvcnkgcGxhbm5pbmcgaG93ZXZlciwgdGhlIGJvb3N0ZWQgY2xhc3NpZmljYXRpb24gdHJlZSB3aWxsIHByb3ZpZGUgbW9yZSB1c2VmdWwgYW5kIGFjY3VyYXRlIHByZWRpY3Rpb25zLiBBbHRob3VnaCB0aGUgZmluYWwgZ3JhZGllbnQgYm9vc3RpbmcgbW9kZWwgcGVyZm9ybXMgd2VsbCwgdGhlcmUgYXJlIHNvbWUgcG9pbnRzIG9mIGltcHJvdmVtZW50IGZvciBmdXR1cmUgaXRlcmF0aW9ucy4gSXQgaXMgcmVjb21tZW5kZWQgdG8gdXNlIG1vcmUgY29tcHV0aW5nIHBvd2VyIHRvIHRyeSBtb3JlIGFuZCBkaWZmZXJlbnQgbW9kZWxzLCB0byBmaW5kIGEgYmV0dGVyIG1vZGVsLiBUaGUgc2VsZWN0ZWQgdmFsdWVzIGZvciB0aGUgdHVuaW5nIHBhcmFtZXRlcnMgd2VyZSBvbiB0aGUgZWRnZSBvZiB0aGUgZ3JpZC4gRm9yIGV4YW1wbGUsIGFuIGludGVyYWN0aW9uIGRlcHRoIG9mIG1vcmUgdGhhbiAzIGNvdWxkIHBvdGVudGlhbGx5IGxlYWQgdG8gYSBiZXR0ZXIgcGVyZm9ybWFuY2UuIEFzIHN1Y2gsIGl0IGlzIHJlY29tbWVuZGVkIHRvIGl0ZXJhdGUgb24gbW9yZSBpbnRlbnNpdmUgbW9kZWxzLiAKCiMgQXBwZW5kaXgKCiMjIFByZXByb2Nlc3NpbmcgcmVjaXBlCgpgYGB7cn0KYm9va2luZ3NfcmVjaXBlIDwtIHJlY2lwZShpc19jYW5jZWxsZWQgfiAuLCBkYXRhID0gYm9va2luZ3NfdHJhaW5fc21hbGwpICU+JQogIHN0ZXBfb3RoZXIoY291bnRyeSwgdGhyZXNob2xkID0gMC4wMSkgJT4lCiAgc3RlcF9vdGhlcihtZWFsLCBtYXJrZXRfc2VnbWVudCwgZGVwb3NpdF90eXBlLCBjdXN0b21lcl90eXBlLCB0aHJlc2hvbGQgPSAwLjAxKSAlPiUKICBzdGVwX2R1bW15KGFsbF9ub21pbmFsKCksIC1pc19jYW5jZWxsZWQpICU+JQogIHN0ZXBfWWVvSm9obnNvbihhbGxfbnVtZXJpYygpKQoKYm9va2luZ3NfcmVjaXBlX3ByZXAgPC0gYm9va2luZ3NfcmVjaXBlICU+JSBwcmVwKGRhdGEgPSBib29raW5nc190cmFpbl9zbWFsbCkKCmJvb2tpbmdzX3RyYWluX2Jha2VkIDwtIGJvb2tpbmdzX3JlY2lwZV9wcmVwICU+JSBiYWtlKG5ld19kYXRhID0gYm9va2luZ3NfdHJhaW5fc21hbGwpCmJvb2tpbmdzX3Rlc3RfYmFrZWQgPC0gYm9va2luZ3NfcmVjaXBlX3ByZXAgJT4lIGJha2UobmV3X2RhdGEgPSBib29raW5nc190ZXN0X3NtYWxsKQpib29raW5nc19maW5hbF90cmFpbl9iYWtlZCA8LSBib29raW5nc19yZWNpcGVfcHJlcCAlPiUgYmFrZShuZXdfZGF0YSA9IGJvb2tpbmdzX3RyYWluKQpib29raW5nc19maW5hbF90ZXN0X2Jha2VkIDwtIGJvb2tpbmdzX3JlY2lwZV9wcmVwICU+JSBiYWtlKG5ld19kYXRhID0gYm9va2luZ3NfdGVzdF9zb2x1dGlvbnMpCmBgYAoKIyMgTW9kZWwgMTogQmFja3dhcmQgc3RlcHdpc2Ugc2VsZWN0aW9uCgpgYGB7cn0Kc2V0LnNlZWQoMTYwMykKc3RlcF9nbG0gPC0gdHJhaW4oaXNfY2FuY2VsbGVkIH4gLiwgCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBib29raW5nc190cmFpbl9iYWtlZCwgCiAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG1TdGVwQUlDIiwgCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IGN0cmwsCiAgICAgICAgICAgICAgICAgIG1ldHJpYyA9ICJST0MiKQpzdGVwX2dsbQpgYGAKCiMjIE1vZGVsIDI6IExhc3NvIHJlZ3Jlc3Npb24KCmBgYHtyfQp0dW5lR3JpZF9sYXNzbyA8LSBleHBhbmQuZ3JpZChhbHBoYSA9IDEsIGxhbWJkYSA9IDEwXihzZXEoZnJvbSA9IC00LCB0byA9IC0yLCBsZW5ndGgub3V0ID0gMjApKSkKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoMTYwMykKbGFzc28gPC0gdHJhaW4oaXNfY2FuY2VsbGVkIH4gLiwgCiAgICAgICAgICAgICAgIGRhdGEgPSBib29raW5nc190cmFpbl9iYWtlZCwgCiAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG1uZXQiLCAKICAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgCiAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IGN0cmwsIAogICAgICAgICAgICAgICB0dW5lR3JpZCA9IHR1bmVHcmlkX2xhc3NvLAogICAgICAgICAgICAgICBtZXRyaWMgPSAiUk9DIikKbGFzc28KYGBgCgpgYGB7cn0KY29lZihsYXNzbyRmaW5hbE1vZGVsLCAwLjAwMjMzNTcyMSkKYGBgCgojIyBNb2RlbCAzOiBEZWNpc2lvbiB0cmVlCgpgYGB7cn0Kc2V0LnNlZWQoMTYwMykKZF90cmVlIDwtIHRyYWluKGlzX2NhbmNlbGxlZCB+IC4sIAogICAgICAgICAgICAgIGRhdGEgPSBib29raW5nc190cmFpbl9iYWtlZCwgCiAgICAgICAgICAgICAgbWV0aG9kID0gInJwYXJ0IiwKICAgICAgICAgICAgICB0dW5lTGVuZ3RoID0gMTAsCiAgICAgICAgICAgICAgdHJDb250cm9sID0gY3RybCwKICAgICAgICAgICAgICBtZXRyaWMgPSAiUk9DIikKZF90cmVlCmBgYAoKIyMgTW9kZWwgNDogQm9vc3RlZCBjbGFzc2lmaWNhdGlvbiB0cmVlCgpgYGB7cn0KdHVuZUdyaWRfeGdiIDwtIGV4cGFuZC5ncmlkKGV0YSA9IGMoMC4wMSwgMC4xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtYXhfZGVwdGggPSAxOjMsIAogICAgICAgICAgICAgICAgICAgICAgICAgY29sc2FtcGxlX2J5dHJlZSA9IDAuNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzYW1wbGUgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3VuZHMgPSBjKDEwMDAsIDI1MDAsIDUwMDApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGdhbW1hID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgIG1pbl9jaGlsZF93ZWlnaHQgPSAxKQpgYGAKCmBgYHtyfQpzZXQuc2VlZCgxNjAzKQp4Z2IgPC0gdHJhaW4oaXNfY2FuY2VsbGVkIH4gLiwgCiAgICAgICAgICAgICBkYXRhID0gYm9va2luZ3NfdHJhaW5fYmFrZWQsIAogICAgICAgICAgICAgbWV0aG9kID0gInhnYlRyZWUiLCAKICAgICAgICAgICAgIHRyQ29udHJvbCA9IGN0cmwsCiAgICAgICAgICAgICB0dW5lR3JpZCA9IHR1bmVHcmlkX3hnYiwKICAgICAgICAgICAgIG1ldHJpYyA9ICJST0MiKQp4Z2IKYGBgCgojIyBEYXRhIHN1bW1hcnkKCmBgYHtyIGVjaG89RkFMU0V9CmJvb2tpbmdzX3RyYWluX3NtYWxsICU+JQogIHNraW0oKSAlPiUKICBrbml0X3ByaW50KCkKYGBgCgojIyBNdWx0aWNvbGxpbmVhcml0eQoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KYm9va2luZ3NfdHJhaW5fc21hbGwgJT4lCiAgc2VsZWN0KGlzLm51bWVyaWMpICU+JQogIGNvcigpICU+JQogIGNvcnJwbG90KHRsLmNleCA9IDAuNSkKYGBgCgojIyBDbGFzcyBkaXN0cmlidXRpb25zIC0gTnVtZXJpYyB2YXJpYWJsZXMKCmBgYHtyIGVjaG89RkFMU0V9CmJvb2tpbmdzX3RyYWluX3NtYWxsICU+JQogIGdyb3VwX2J5KGlzX2NhbmNlbGxlZCkgJT4lCiAgc2tpbSgpICU+JQogIGtuaXRfcHJpbnQoKQpgYGAKCiMjIENhdGVnb3JpY2FsIHZhcmlhYmxlcwoKYGBge3IgZWNobz1GQUxTRX0KYm9va2luZ3NfdHJhaW5fc21hbGwgJT4lIGNvdW50KGNvdW50cnkpICU+JSBoZWFkKDEwKSAlPiUga2FibGUoKSAlPiUga2FibGVfc3R5bGluZygpCmJvb2tpbmdzX3RyYWluX3NtYWxsICU+JSBjb3VudChhcnJpdmFsX2RhdGVfbW9udGgpICU+JSBrYWJsZSgpICU+JSBrYWJsZV9zdHlsaW5nKCkKYm9va2luZ3NfdHJhaW5fc21hbGwgJT4lIGNvdW50KG1lYWwpICU+JSBrYWJsZSgpICU+JSBrYWJsZV9zdHlsaW5nKCkKYm9va2luZ3NfdHJhaW5fc21hbGwgJT4lIGNvdW50KG1hcmtldF9zZWdtZW50KSAlPiUga2FibGUoKSAlPiUga2FibGVfc3R5bGluZygpCmJvb2tpbmdzX3RyYWluX3NtYWxsICU+JSBjb3VudChkZXBvc2l0X3R5cGUpICU+JSBrYWJsZSgpICU+JSBrYWJsZV9zdHlsaW5nKCkKYm9va2luZ3NfdHJhaW5fc21hbGwgJT4lIGNvdW50KGN1c3RvbWVyX3R5cGUpICU+JSBrYWJsZSgpICU+JSBrYWJsZV9zdHlsaW5nKCkKYGBgCg==